美文网首页让前端飞Web前端之路前端开发那些事
30分钟快速过一遍Webpack4核心知识

30分钟快速过一遍Webpack4核心知识

作者: JokerPeng | 来源:发表于2019-05-26 17:46 被阅读0次

    1、webpack和webpack-dev-server区别

    webpack 每次会生成一个bundle.js文件,webpack-dev-server不会,只是将打包结果放在内存中,并不会写入实际的bundle.js,在每次webpack-dev-server接收到请求时,都将内存中的打包结果返回给浏览器。

    2、webpack-cli安装后可以直接在控制台调用webpack命令

    3、url-loader 和 file-loader

    url-loaderfile-loader都可以用来作为打包图片的loader

    • url-loader不会生成一个具体的图片文件,而是直接在需要这个图片src地址的地方给出图片的base64地址,这样比较适合几k大小的小图,减少http请求;url-loader有个limit设置一个numer,单位是bytes,如果图片大于这个limit值,则默认使用file-loader, 如果小于则使用url-loader
    • file-loader会生成一个图片文件,适合大点的图片

    4、style-loader作用主要是将css放到dom中

    官方英文解释很到位:Adds CSS to the DOM by injecting a <style> tag

    如果配置style-loader/url,则会生成一个类似<link rel="stylesheet" href="path/to/file.css">这样的内联css。

    5、postcss-loader与Autoprefixer一起,用来适配各大浏览器厂商css前缀

    • 需要配置postcss.config.js,和安装autoprefixer

    6、模块样化处理

    {
      loader: 'css-loader',
      options: {
        importLoaders: 2,
        modules: true,
      },
    },
    

    如上在配置css-loader时候,配置modules: true

    但一般出路antd的样式时候,需要做两手处理:

    {
        test: /\.less$/,
        include: /node_modules\/antd/,
        use: [
            'style-loader',
            { loader: 'css-loader', options: {modules: false} },
            'less-loader'
        ]
    },
    {
        test: /\.less$/,
        exclude: /node_modules\/antd/,
        use: [
            'style-loader',
            { loader: 'css-loader', options: {modules: true} },
            'less-loader'
        ]
    }
    

    这样避免了 css-modules 对 antd 的样式进行处理,否则会造成antd 的样式的不匹配。

    7、iconfont字体打包

    {
        test: /\.(eot|ttf|svg|woff)$/,
         use: {
            loader: 'file-loader',
        },
    }
    

    如上示例,打包.eot, .ttf等字体文件

    8、html-webpack-plugin

    • 会在打包完成后,自动生成一个html文件,并把打包生成的js自动引入到这个html中
    • 如果希望打包出来的html是按照要求配置的,如加上<div id="root"></div>,那么就可以在HtmlWebpackPlugin配置中加入template指定一个模板文件

    9、clean-webpack-plugin

    • 清除打包数据
    • clean-webpack-plugin v3.0以上版本,不需要添加额外配置项,默认清除的文件是output.path指定的路径文件夹内容

    10、output.publicPath

    • output中配置publicPath,如一个路径或者一个cdn地址,然后打包出来的资源会自动加上这个publicPath前缀,如加上一个cdn的host后,打包出来的script的src会在文件名前加上这个cdn地址。

    11、source-map

    • souce-map是源代码和打包后的代码的一个映射关系,对应的webpack配置是devtool,可以快速定位错误行代码。
    • devtoolmode=development中一般配置,devtool:cheap-module-eval-source-map,这样既可以定位错误正确的位置,同时打包速度也不会太受影响。
    • devtoolmode=production中一般配置,devtool:cheap-module-source-map
    • devtool设置了source-map会生成一个.map映射文件;
    • 设置了带inline,则会将映射文件内容放到打包文件里,不会单独生成.map映射文件;
    • 设置了带cheap的配置只会提示行不提示列错误,同时只提示业务代码,不管loader的打包代码;
    • 设置了带module的是除了核心业务代码,loader打包文件代码也会提示错误位置
    • 设置了带eval的会提高打包速度。

    12、devServer

    • 主要用于快速开发应用,提高开发效率
    • 通过设置package.json中的stripts,"watch": "webpack --watch",可以实现修改页面代码后自动打包,但是没法开启一个服务,这就不能满足ajax(ajax必须在一个http服务里才能使用)调用服务等开发需求了,此时需要webpack-dev-server
    • webpack-dev-server打包出来的文件不会放到原先的dist或者配置好的output路径,而是放到了本地电脑内存中,这样提升打包速度
    • 配置contentBase,告诉服务器从哪个目录中提供内容,填写output的path就可以了
    • 配置open,设为true时devserver启动后自动打开浏览器
    • 配置port,可以修改开启服务的端口号
    • 配置proxy,如果现在在http://localhost:3000上有服务端的话,可以设置proxy: {'/api': 'http://localhost:3000'},这样在本地的非3000端口host上请求/api/info接口,实际是请求了http://localhost:3000/api/info,否则会报跨域错误
    • 如果不用 webpack-dev-server,可以通过 webpack-dev-middleware 和express/koa2写一个server.js的服务,然后启动这个服务,可以达到和 webpack-dev-server 一样的修改后自动更新等效果

    13、hot-module-replacement

    • 当添加了 webpack-dev-server 之后,那么每次有代码修改时,就会重新请求页面,然后刷新页面,但这有个小问题,就是即便一个css颜色值修改了,页面也会重新刷新,加入hot-module-replacement可以简化这个请求过程。
    • 首先在devServer中加入 hot:true,然后在 plugins 中加入new webpack.HotModuleReplacementPlugin()配置,这样仅仅只能做到css样式的无刷新修改
    • 如果需要js也能无刷新修改,则需要在js中加入module.hot的判断,判断的对应结果中需要更新代码,使用 module.hot.accept 将其绑定到新的函数执行中,详见https://webpack.docschina.org/guides/hot-module-replacement/#%E5%90%AF%E7%94%A8-hmr
    • 具体针对前端不同框架,社区有不同loader可以支持HMR,React Hot LoaderVue loader

    14、配置Babel

    • Babel主要是将es6+代码转换为es5代码,让低版本浏览器也能加载代码
    • ① 最基本的设置是:

    npm install --save-dev babel-loader @babel/core

    webpack 设置:

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

    .babelrc 文件设置如下:

    npm install @babel/preset-env --save-dev

    {
        "presets": ["@babel/preset-env"]
    }
    

    但面对更低版本的浏览器的时候,像promise还需要转化注入,就需要引入babel/polyfill


    • npm install --save @babel/polyfill

    在对应业务js代码文件开头引入polyfill import "@babel/polyfill";

    但是这样有个缺点,就是会把所有es6转es5的需要的语法都给打包到对应文件,造成打包文件过大。

    如果需要按需去打包polyfill语法,根据代码需要,可以设置文件 .babelrc

    {
        "presets": [["@babel/preset-env", {
        "targets": {
            chrome: "67"
        },
        "useBuiltIns": "usage",
        }]],
    }
    

    上面配置中的 targets 中配置的浏览器版本,是指大于该版本的浏览器,根据该浏览器对es6的支持情况去有针对性的打包polyfill代码,这样可以让打包文件变得更小一点,比如如果chrome67以上的版本浏览器对promise支持很好,那么就不需要打包promise的语法了,更不需要对promise去转码。

    总的来说,polyfill修改了全局作用域,浏览器下是window,node下是global。

    babel-polyfill主要由两部分组成,core-js和regenerator runtime。

    core-js:提供了如ES5、ES6、ES7等规范中 中新定义的各种对象、方法的模拟实现。
    regenerator:提供generator支持,如果应用代码中用到generator、async函数的话用到。

    引入babel-polyfill全量包后文件会变得非常大。

    • ③ 以上方式需要在对应入口js文件开头引入polyfillimport "@babel/polyfill";
      这种方式会产生一些全局变量,代码量大了之后如写一个大型库或者ui组件库等全局变量会产生变量污染全局。这样就需要用到 transform-runtime,它不会污染全局环境:

    npm install --save-dev @babel/plugin-transform-runtime

    npm install --save @babel/runtime @babel/runtime-corejs2

    删除对应文件开头的引入 import "@babel/polyfill";

    .babelrc 文件设置如下:

    {
        "plugins": [["@babel/plugin-transform-runtime",
          {
            "absoluteRuntime": false,
            "corejs": 2,
            "helpers": true,
            "regenerator": true,
            "useESModules": false,
          }]],
    }
    

    @babel/plugin-transform-runtime 会以闭包的形式

    15、Tree Shaking

    • Tree Shaking 用来检测项目中没有被引用的代码(dead-code),Webpack会对这部分代码进行标记,然后在资源压缩打包的时候,从打包出来的文件中去掉,如下示例:
    // outer.js
    
    export const foo = () => {
      console.log('Fucked Up');
    };
    
    export const bar = () => {
      console.log('Beyond All Repair');
    };
    
    
    // index.js
    import { foo } from './outer';
    
    foo();
    

    然后配置webpack.config.js文件,添加如下modeoptimization2个配置:

    // webpack.config.js
    mode: 'development',
    optimization: {
        usedExports: true,
    },
    

    然后打包,打开打包好的文件,可以看到如下部分:

    /***/ "./src/outer.js":
    /*!**********************!*\
      !*** ./src/outer.js ***!
      \**********************/
    /*! exports provided: foo, bar */
    /*! exports used: foo */
    /***/ (function(module, __webpack_exports__, __webpack_require__) {
    
    "use strict";
    eval("/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return foo; });\n/* unused harmony export bar */\nvar foo = function foo() {\n  console.log('Fucked Up');\n};\nvar bar = function bar() {\n  console.log('Beyond All Repair');\n};//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9zcmMvb3V0ZXIuanMuanMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9zcmMvb3V0ZXIuanM/NGJlZiJdLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgY29uc3QgZm9vID0gKCkgPT4ge1xuICBjb25zb2xlLmxvZygnRnVja2VkIFVwJyk7XG59O1xuXG5leHBvcnQgY29uc3QgYmFyID0gKCkgPT4ge1xuICBjb25zb2xlLmxvZygnQmV5b25kIEFsbCBSZXBhaXInKTtcbn07XG4iXSwibWFwcGluZ3MiOiJBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0EiLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./src/outer.js\n");
    
    /***/ })
    

    其中有2行注释说明了:

    /*! exports provided: foo, bar */
    /*! exports used: foo */
    

    就是打包文件中还是导出了foobar两个方法,但只用到了foo,这说明在development中代码的tree shaking只是找出来了并告知了,但并没有真的去删除这部分没用到的代码,webpack4新增了mode,将其设置为production后,不用设置optimization,就会真实执行tree shaking

    // webpack.config.js
    mode: 'production',
    

    因为设置了mode: 'production'后代码被作了minify(压缩)mangle(混淆破坏)foobar方法已经搜不到了,但是方法体中的console内容还是可以搜的,可以发现,foo中的console内容Fucked Up还可以搜到,而bar中的console内容Beyond All Repair已经搜不到了,因为已经被删除了。

    webpack4新增了一个例外处理的口子,就是在package.json中配置一个sideEffects属性,来设置哪些文件是永远都不会被删除掉的,如果设置了sideEffects: false,那么则会正常的删除未被用到的代码。如果设置了sideEffects: ["@babel/polly-fill"]则表明,即便@babel/polly-fill没被直接应用,但还是会在打包时,将它打包进来。

    • Tree Shaking的注意事项(来至官网):
      • 使用 ES2015 模块语法(即 import 和 export)。
      • 确保没有 compiler 将 ES2015 模块语法转换为 CommonJS 模块(这也是流行的 Babel preset 中 @babel/preset-env 的默认行为)。
      • 在项目 package.json 文件中,添加一个 "sideEffects" 属性。
      • 通过将 mode 选项设置为 production ,启用 minification (代码压缩) 和 tree shaking

    16、Mode: development/production

    wenpack4新增了mode配置:

    • 设置mode: 'development'
      • 会将 process.env.NODE_ENV 的值设为 development
      • 启用 NamedChunksPluginNamedModulesPlugin
    • 设置mode: 'production'
      • 会将 process.env.NODE_ENV 的值设为 production
      • 启用 FlagDependencyUsagePlugin
      • FlagIncludedChunksPlugin
      • ModuleConcatenationPlugin
      • NoEmitOnErrorsPlugin
      • OccurrenceOrderPlugin
      • SideEffectsFlagPlugin
      • UglifyJsPlugin

    相关文章

      网友评论

        本文标题:30分钟快速过一遍Webpack4核心知识

        本文链接:https://www.haomeiwen.com/subject/eksftctx.html