webpack4学习笔记

快速上手

  1. npm init -y

  2. npm install webpack webpack-cli -D

  3. 调整 package.json 文件,确保安装包是私有的(private),并且移除 main 入口。可防止意外发布代码

    {
        +  "private": true,
        -  "main": "index.js",
    }
    
  4. 使用webpack
    ① 配置webpack.config.js 或 (npx webpack --config 自定义文件名)

    var path = require('path');
    
    module.exports = {
       mode: 'production',
       entry: './src/index.js',  
       /**
       entry: {
                main: './src/index.js'
              }
       **/
       output: {
           filename: 'bundle.js',
           path: path.resolve(__dirname, 'dist')
       }
    }
    

② package.json中找到script新增"bundle": "webpack"

"scripts": {
  "bundle": "webpack",
}

npm run bundle

loader 配置

  1. 图片、视频、字体文件打包 url-loader
npm install url-loader -D
module.exports = {
   module: {
       rules: [
         {
           test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
           use: [{
                loader: 'url-loader',
                 options: {
                    name: 'img/[name]_[hash:7].[ext]',
                    limit: 10000 // 小于10000的生成base64
                 }
           }]
         },
         {
            test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
            use: [{
                 loader: 'url-loader',
                 options: {
                    limit: 10000,
                    name: 'media/[name]_[hash:7].[ext]',
                    }
              }]
         },
         {
           test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
           use: [{
              loader: 'url-loader',
              options: {
                  limit: 10000,
                   name: 'fonts/[name].[hash:7].[ext]',
                    }
                }]
            }
        ]
   }
}
  1. css打包并添加前缀 style-loader css-loader postcss-loader autoprefixer
npm i style-loader css-loader postcss-loader autoprefixer -D

添加postcss.config.js

module.exports = {
    plugins: [
        require('autoprefixer')
    ]
}

package.json中增加browserslist选项(必须添加,不然添加不上兼容性前缀)

{
    "browserslist": [
        "> 1%",
        "last 2 versions",
        "not ie <= 8"
    ]
}

webpack.config.js中增加loader

module.exports = {
   module: {
       rules: [{
           test: /\.css$/,
           use: [
           'style-loader',
           {
               loader: 'css-loader',
               options: {
                   importLoaders: 1 // 引入文件时使用
               }
           },
           'postcss-loader'
           ]
       }]
   }
}
  1. less文件打包 less-loader
// 提前安装style-loader和css-loader
npm install less-loader less -D 
module.exports = {
   module: {
       rules: [{ 
           test: /\.less$/,
           use: ['style-loader','css-loader','less-loader']
       }]
   }
}
  1. scss文件打包 sass-loader
// 提前安装style-loader和css-loader和postcss-loader和autoprefixer
npm install sass-loader node-sass webpack -D 
module.exports = {
   module: {
       rules: [{ 
           test: /\.scss$/,
           use: [
                  'style-loader',
                  {
                      loader: 'css-loader',
                      options: {
                          importLoaders: 2
                      }
                  },
                  'postcss-loader', // 经测试需放在sass-loader后
                  'sass-loader'
              ]
       }]
   }
}

plugins使用

  1. html-webpack-plugin
npm install --save-dev html-webpack-plugin

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');
export.modules = {
   plugins: [
     new HtmlWebpackPlugin({
       title: 'Output Management',
       template: 'src/index.html'
     })
   ],
}
  1. clean-webpack-plugin
npm install --save-dev clean-webpack-plugin

webpack.config.js

const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
    plugins: [
     new CleanWebpackPlugin()
    ]
  };

devtool配置

source-map(最慢) 在js文件下多了.map.js文件
inline-source-map 【inline】.map.js文件被打包到了页面引入的js文件中
cheap-inline-source-map【cheap】打包性能提升①不用精确到列②只管业务代码,不管引入的第三方模块代码
cheap-module-inline-source-map【module】不仅需要检查业务代码,而且需要检查引入的第三方模块代码
eval(最快)复杂的代码提示可能不全
最优配置方案

// 开发环境
module.exports = {
   mode: 'development',
   devtool: 'cheap-module-eval-source-map'
}
// 生产环境
module.exports = {
   mode: 'production',
   devtool: 'cheap-module-source-map'
}

开发环境启动

  1. sourceMap
    webpack.config.js
module.exports = {
   mode: 'development',
   devtool: 'cheap-module-eval-source-map'
}
  1. watch Mode
    package.json
"scripts": {
   "watch": "webpack --watch"
}
  1. webpack-dev-server(推荐)
npm install webpack-dev-server -D

webpack.config.js

module.exports = {
   devServer: {
      contentBase: './dist',
      open: true,
      port: 8080 // 默认8080,可更改
   // proxy: {
   //     '/api': {
   //         target: 'http://localhost:3000',
   //         pathRewrite: {'^/api': ''}
   //     }
   // }
   }
};

package.json

"scripts": {
    "start": "webpack-dev-server"
}
  1. webpack-dev-middleware
npm install --save-dev express webpack-dev-middleware

project 增加server.js

  |- package.json
  |- webpack.config.js
+ |- server.js
  |- /dist
  |- /src
    |- index.js
    |- print.js
  |- /node_modules

server.js

const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');

const app = express();
const config = require('./webpack.config.js');
const compiler = webpack(config);

// Tell express to use the webpack-dev-middleware and use the webpack.config.js
app.use(webpackDevMiddleware(compiler, {}));

// Serve the files on port 3000.
app.listen(3000, function () {
  console.log('Example app listening on port 3000!\n');
});

package.json

"scripts": {
   "server": "node server.js"
},

热更新(Hot Module Replacement)

eg: D:\学习视频\webpack\源码\02-09_hot_module_replacement
webpack.config.js

const webpack = require('webpack');
module.exports = {
    devServer: {
    +   hot: true,
    +   hotOnly: true // 即使HMR不生效、浏览器也不自动刷新
    },
    plugins: [
    +   new webpack.HotModuleReplacementPlugin()
    ]
}

index.js

if(module.hot) {
    module.hot.accept('./number', () => {
        document.body.removeChild(document.getElementById('number'));
        number();
    })
}

babel配置

安装

npm install  babel-loader @babel/core -D
npm install  @babel/preset-env -D

npm install  @babel/plugin-transform-runtime -D
npm install  @babel/runtime @babel/runtime-corejs3 -S

webpack.config.js

module: {
  rules: [
    { 
       test: /\.js$/, 
       exclude: /node_modules/,
       loader: "babel-loader"
    }
  ]
}

.babelrc

{
  "presets": [
    [
      "@babel/preset-env", // 智能预设,翻译最新的js语法
      {
        "targets": {
          "browsers": [
            "> 1%",
            "last 2 version",
            "not ie<=8"
          ]
        }
      }
    ]
  ],
  "plugins": [
    [
      "@babel/plugin-transform-runtime", //翻译corejs中用到的垫片
      {
        /*
        corejs: boolean或number,默认为false。 
        corejs:false 不转换垫片;
        corejs:2 转换垫片,不支持实例方法
        corejs:3 转换垫片,支持实例方法 
        */
        "corejs": "3", 
        "helpers": true,
        "regenerator": true,
        "useESModules": false
      }
    ]
  ]
}

使用@babel/plugin-transform-runtime而不是useBuiltIns:'usage'的原因是plugin-transform-runtime①避免重复代码 ②防止全局污染

Tree Shaking

去除引入模块中没有引入的代码
只支持ES Module静态模块的引入(import XX from XX)
package.json

{
  "name":"learn-webpack",
+ "sideEffects": [ // 不进行Tree shaking的文件
   "*.css"
  ]
}

webpack.config.js

- mode: 'development',
- optimization: {
-   usedExports: true // 被使用的文件进行打包
- }
+ mode: 'production'

development和production打包文件配置

  • 把webpack.config.js拆成公共、dev、prod三份配置文件
  • 安装merge插件cnpm i webpack-merge -D,dev和prod文件中merge公共文件
  • package.json里配置打包方式
"scripts": {
  "dev": "webpack-dev-server --config ./build/webpack.dev.js",
  "build": "webpack --config ./build/webpack.prod.js"
}

code splitting

三种方式:通过配置entry、同步加载分割、异步加载分割
1. entry
提前安装lodash插件npm i lodash -S
lodash.js

import _ from 'lodash';
window._ = _;

main.js

_.join(['hello','splitting'],',');

webpack entry配置

{
  entry: {
     lodash:'./src/lodash.js',
     main:'./src/main.js'
  }
}

2. 同步加载
webpack optimization配置

optimization: {
    splitChunks: { 
      chunks:'all'
   }
}

main.js

import _ from 'lodash';
_.join(['hello','splitting'],',');

3. 异步加载(无需任何配置,会自动进行代码拆分)

 async function getComponent() {
    const element = document.createElement('div');
    const {default: _} = await import(/* webpackChunkName: "lodash" */ 'lodash');
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');

    return element;
}

getComponent().then(component => {
    document.body.appendChild(component);
});

splitChunks

webpack.config.js

optimization: {
 splitChunks: {
   chunks: 'all', // initial 同步  async 异步  all 同步、异步
   minSize: 30000, // 超过30kb才拆分打包
   // maxSize: 0, // 一般不配置
   minChunks: 1, // 最少使用一次
   maxAsyncRequests: 5, // 同时加载的模块数最多是5个
   maxInitialRequests: 3, // 首页引入最多拆分3个代码块
   automaticNameDelimiter: '~', // 组合文件之间连接符
   automaticNameMaxLength: 30,
   name: true, // 是否支持命名
   cacheGroups: { // 添加或覆盖splitChunks中的属性
     vendors: {
        test: /[\\/]node_modules[\\/]/,
         priority: -10, // 优先级(不同文件夹间比较)
         name: 'vendors' // filename:只针对initial方式,否则报错
      },
      default: {
        minChunks: 1,
         priority: -20,
         reuseExistingChunk: true, // 已经打包过的文件不再重新打包
         name: 'commons'
      }
   }
 }
}

懒加载文件

function getComponent() {
  return import(/* webpackChunkName: "lodash" */ 'lodash').then(({default: _}) => {
        var element = document.createElement('div');
        element.innerHTML = _.join(['Hello', 'webpack'], ' ');
        return element;
    });
}

document.addEventListener('click', function () {
    getComponent().then(element => {
        document.body.appendChild(element);
    });
})

注:函数写成async - await 的方式,打包时直接会把引入的文件打包,没有实现懒加载

css 打包

cnpm install -D mini-css-extract-plugin // 拆分css
cnpm install -D terser-webpack-plugin // 压缩
cnpm install -D optimize-css-assets-webpack-plugin // 压缩

webpack.prod.js

const TerserJSPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
    module: {
        rules: [
           {
             test: /\.css$/,
               use: [
                   MiniCssExtractPlugin.loader, // MiniCssExtractPlugin.loader替换原有的style-loader
                   'css-loader',
                   'postcss-loader'
               ]
            },
         ]
    },
    optimization: {
        minimizer: [
            new TerserJSPlugin({}),
            new OptimizeCSSAssetsPlugin({})
        ],
        splitChunks: {
            cacheGroups: {
                styles: {
                    name: 'styles',
                    test: /\.css$/,
                    chunks: 'all',
                    enforce: true
                }
            }
        }
    },
    plugins: [
        new MiniCssExtractPlugin()
    ]
}

代码优化

1.打包分析 http://www.github.com/webpack/analyse

① 生成打包分析json文件

webpack --profile --json > stats.json

http://webpack.github.com/analyse上传json可查看分析结果

2.控制台Run Command(Ctrl+shift+p) Show coverage 查看代码使用率

3.代码异步加载
eg: 新建click.js

function click() {
    const element = document.createElement('div');
    element.innerHTML = 'vivian';
    document.body.appendChild(element);
}

export default click;

main.js
**webpackPrefetch:true **
可在任务完成后,带宽空闲时提前加载js

document.addEventListener('click', function () {
   import(/* webpackPrefetch:true */'./click.js')
   .then(({default: func}) => {
        func();
    });
})

浏览器缓存

去除打包时性能提示 webpack配置中增加performance:false

为了防止更新文件后,浏览器缓存。在输出文件夹加contenthash

  output: {
      filename: '[name].[contenthash:7].js',
      chunkFilename: '[name].[contenthash:7].js',
  },
  optimization:{
     runtimeChunk: { // 解决老版本依赖文件生成不同hash值的办法
         name: 'runtime'
     },
     splitChunks: { // 打包出vendors文件
        chunks: 'all',
        cacheGroups: {
            vendors: {
                test: /[\\/]node_modules[\\/]/,
                priority: -10,
                name: 'vendors'
            }
        }
     }
  }

shimming

const webpack = require('webpack');
plugins:[
    new webpack.ProvidePlugin({
        $:'jquery'
    })
]

devServer

devServer: {
    contentBase: './dist',
    open: true,
    port: 8080, // 默认8080,可更改
    hot: true,
    proxy: {
       '/api': {
           target: 'http://localhost:3000',
           secure: false, // true时,接受运行在 HTTPS 上
           pathRewrite: {'^/api': ''},
           changeOrigin: true, // 突破有些接口对origin限制
           headers:{
             host:'www.baidu.com'
           }
       }
    }
}

代理多个路径特定到同一个 target 下

module.exports = {
  //...
  devServer: {
    proxy: [{
      context: ['/auth', '/api'],
      target: 'http://localhost:3000',
    }]
  }
};

webpack打包优化

  1. 更新webpack、node版本
  2. loader范围缩小
{
    test: /\.js$/, 
        exclude:/node_modules/,
        // include:path.resolve(__dirname,'./src'),
        use: [{
            loader: 'babel-loader'
        }, {
            loader: 'imports-loader?this=>window'
        }]
}
  1. 插件的合理使用
    eg:生成环境不使用压缩css插件、使用官方插件等;
  2. 文件引入方式
resolve:{
    extensions:['.js','.jsx'], // 省略后缀
    mainFiles:['index','child'], // 省略文件名(不常用)
    alias:{ // 别名
        child:path.resolve(__dirname,'../src/a/b/c/child')
    }
}
import child from 'child';
  1. 引入第三方文件打包到一个文件中
  • 生成dll文件
    webpack.dll.js
const path = require('path');
const webpack = require('webpack');

module.exports = {
    mode: 'production',
    entry: {
        vendors: ['lodash'],
        react: ['react', 'react-dom'],
        jquery: ['jquery']
    },
    output: {
        filename: '[name].dll.js',
        path: path.resolve(__dirname, '../dll'),
        library: '[name]'
    },
    plugins: [
        new webpack.DllPlugin({
            name: '[name]',
            path: path.resolve(__dirname, '../dll/[name].mainfest.json')
        })
    ]
}
  • 指向生成的dll文件并挂载到html上
npm i add-asset-html-webpack-plugin -S
var path = require('path');
const fs = require('fs');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');

const plugins = [
    new HtmlWebpackPlugin({
        title: 'Output Management',
        template: 'src/index.html'
    }),
    new CleanWebpackPlugin(),
    new webpack.ProvidePlugin({
        $: 'jquery'
    })
];

const files = fs.readdirSync(path.resolve(__dirname, '../dll'));
files.forEach(file => {
    if (/.*\.dll.js/.test(file)) {
        plugins.push(new AddAssetHtmlWebpackPlugin({ // 挂载到html上
            filepath: path.resolve(__dirname, '../dll', file)
        }))
    }
    if (/.*\.manifest.json/.test(file)) {
        plugins.push(new webpack.DllReferencePlugin({ // 指向生成的dll文件
            manifest: path.resolve(__dirname, '../dll', file)
        }))
    }
})
module.exports = {
    plugin
}
  1. 控制包大小
  2. thread-loader,parallel-webpack,happypack多进程打包
  3. 合理使用sourceMap
  4. 结合stats分析打包结果
  5. 开发环境内存编译
  6. 开发环境无用插件剔除

多页面打包

plugins.push(new HtmlWebpackPlugin({ // 多页面配置多个htmlWebpackPlugin
    template: 'src/index.html',
    filename: `${item}.html`, // 输出文件名
    chunks: ['vendors', item] // 文件引入的js
}))
const makePlugin = (configs) => {
    const plugins = [
        new CleanWebpackPlugin()
    ];

    Object.keys(configs.entry).forEach(item => {
        plugins.push(new HtmlWebpackPlugin({
            template: 'src/index.html',
            filename: `${item}.html`,
            chunks: ['vendors', item]
        }))
    });

    const files = fs.readdirSync(path.resolve(__dirname, '../dll'));
    files.forEach(file => {
        if (/.*\.dll.js/.test(file)) {
          plugins.push(new AddAssetHtmlWebpackPlugin({
             filepath: path.resolve(__dirname, '../dll', file)
          }))
        }
        if (/.*\.manifest.json/.test(file)) {
          plugins.push(new webpack.DllReferencePlugin({
             manifest: path.resolve(__dirname, '../dll', file)
          }))
        }
    });
    return plugins;
};

自定义loader

  1. 新建make-loader文件夹 ---> npm init -y
  2. npm i webpack webpack-cli -D
  3. webpack.config.js
const path = require('path');

module.exports = {
    mode: 'development',
    entry: {
        main: './src/index.js'
    },
    resolveLoader: {
        modules: ['node_modules', './loaders']
    },
    module: {
        rules: [{
            test: /\.js/,
            use: [
                {
                    loader: 'replaceLoader'
                },
                {
                    loader: 'replaceLoaderAsync',
                    options: {
                        name: 'vv'
                    }
                }
            ]
        }]
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js'
    }
}
  1. 自定义loader
    npm i loader-untils -D
    replaceLoaderAsync.js
const loaderUtils = require('loader-utils');

module.exports = function (source) {
    const options = loaderUtils.getOptions(this);
    const callback = this.async();

    setTimeout(() => {
        const result = source.replace('vivian', options.name);
        callback(null, result);
    }, 1000)
}

replaceLoader.js

module.exports = function (source) {
    return source.replace('vv','vv2');
}
  1. package.json
{
    "build":"webpack"
}

npm run build

自定义plugin

  1. 新建make-plugin文件夹 ---> npm init -y
  2. npm i webpack webpack-cli -D
  3. 自定义plugin
    copyright-webpack-plugin.js
class CopyRightWebpackPlugin {
    apply(compiler) {
        compiler.hooks.compile.tap('CopyrightWebpackPlugin', (compilation) => {
            console.log('complier');
        })

        compiler.hooks.emit.tapAsync('CopyrightWebpackPlugin', (compilation, cb) => {
            compilation.assets['copyright.text'] = {
                source: function () {
                    return 'copyright by vivian'
                },
                size: function () {
                    return 19;
                }
            }
            cb();
        })
    }
}

module.exports = CopyRightWebpackPlugin
  1. webpack.config.js
const path = require('path');
const CopyRightWebpackPlugin = require('./plugins/copyright-webpack-plugin');

module.exports = {
    mode: 'development',
    entry: {
        main: './src/index.js'
    },
    plugins: [
        new CopyRightWebpackPlugin()
    ],
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js'
    }
}
  1. package.json
{
    "build":"webpack"
}

npm run build

配置eslint

npm i eslint eslint-loader -D

生成.eslintrc.js初始化文件

npx eslint --init 

webpack.config.js

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [
          'babel-loader',
          {
            loader: 'eslint-loader',
            options: 'fix',
            force: 'pre' // 最先执行
          }
         ],
      },
    ],
  },
  devServer: {
      overlay: true, // 弹窗显示报错
      contentBase: './dist',
      open: true,
      port: 8089
 },
 // ...
};
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • 全局安装webpack 全局安装webpack会有个问题,就是当你有两个项目依赖于不同版本的webpack,就会有...
    説好的妹紙呢阅读 1,803评论 0 11
  • 前言 本文主要从webpack4.x入手,会对平时常用的Webpack配置一一讲解,各个功能点都有对应的详细例子,...
    BetterChen阅读 1,943评论 0 3
  • webpack使用学习 本分享学习借鉴webpack中文官网,官网链接(中文文档):https://www.web...
    腿毛怪丶叔叔阅读 866评论 0 5
  • 关于CMake CMake 是一个跨平台的自动化建构系统,它使用一个名为 CMakeLists.txt 的文件来描...
    Pokerpoke阅读 932评论 0 0
  • 秋,已然走远。不过,手机里的拍照,立马就会把秋拉回眼前。 拾起遗落小景,放松一下心情。 认识拉拉藤吧?是挺讨厌的,...
    萍一简阅读 1,164评论 25 40