最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 前端模块化-webpack

    正文概述 掘金(恍惚之间)   2021-01-07   620

    webpack

    工作模式

    webpack.js.org/configurati…

    用法

    mode在配置中提供选项:

    module.exports = {
      mode: 'development'
    };
    

    或将其作为CLI参数传递:

    webpack --mode=development
    

    开发模式

    // webpack.development.config.js
    module.exports = {
    + mode: 'development'
    - devtool: 'eval',
    - cache: true,
    - performance: {
    -   hints: false
    - },
    - output: {
    -   pathinfo: true
    - },
    - optimization: {
    -   moduleIds: 'named',
    -   chunkIds: 'named',
    -   mangleExports: false,
    -   nodeEnv: 'development',
    -   flagIncludedChunks: false,
    -   occurrenceOrder: false,
    -   concatenateModules: false,
    -   splitChunks: {
    -     hidePathInfo: false,
    -     minSize: 10000,
    -     maxAsyncRequests: Infinity,
    -     maxInitialRequests: Infinity,
    -   },
    -   emitOnErrors: true,
    -   checkWasmTypes: false,
    -   minimize: false,
    -   removeAvailableModules: false
    - },
    - plugins: [
    -   new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),
    - ]
    }
    

    生产模式

    // webpack.production.config.js
    module.exports = {
    +  mode: 'production',
    - performance: {
    -   hints: 'warning'
    - },
    - output: {
    -   pathinfo: false
    - },
    - optimization: {
    -   moduleIds: 'deterministic',
    -   chunkIds: 'deterministic',
    -   mangleExports: 'deterministic',
    -   nodeEnv: 'production',
    -   flagIncludedChunks: true,
    -   occurrenceOrder: true,
    -   concatenateModules: true,
    -   splitChunks: {
    -     hidePathInfo: true,
    -     minSize: 30000,
    -     maxAsyncRequests: 5,
    -     maxInitialRequests: 3,
    -   },
    -   emitOnErrors: false,
    -   checkWasmTypes: true,
    -   minimize: true,
    - },
    - plugins: [
    -   new TerserPlugin(/* ... */),
    -   new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
    -   new webpack.optimize.ModuleConcatenationPlugin(),
    -   new webpack.NoEmitOnErrorsPlugin()
    - ]
    }
    

    none模式

    // webpack.custom.config.js
    module.exports = {
    + mode: 'none',
    - performance: {
    -  hints: false
    - },
    - optimization: {
    -   flagIncludedChunks: false,
    -   occurrenceOrder: false,
    -   concatenateModules: false,
    -   splitChunks: {
    -     hidePathInfo: false,
    -     minSize: 10000,
    -     maxAsyncRequests: Infinity,
    -     maxInitialRequests: Infinity,
    -   },
    -   emitOnErrors: true,
    -   checkWasmTypes: false,
    -   minimize: false,
    - },
    - plugins: []
    }
    

    根据webpack.config.js中的mode变量更改行为

    var config = {
      entry: './app.js'
      //...
    };
    
    module.exports = (env, argv) => {
    
      if (argv.mode === 'development') {
        config.devtool = 'source-map';
      }
    
      if (argv.mode === 'production') {
        //...
      }
    
      return config;
    };
    

    loader

    编译转换类

    css-loader

    前端模块化-webpack 前端模块化-webpack

    babel-loader

    webpack需要完成模块打包,默认会转换es6的import、export;对于箭头函数、const等es6语法则不处理。 前端模块化-webpack 前端模块化-webpack

    // webpack.config.js
    module: {
      rules: [
        {
          test: /.js$/,
          use: {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env']
            }
          }
        }
      ]
    }
    

    添加babel-loader并配置转换规则后,const声明和箭头函数被转换成var以及普通函数,如下图: 前端模块化-webpack

    文件操作类

    file-loader

    style-loader

    url-loader

    适合体积比较小的资源,减少请求发送次数;较大文件通过文件方式加载,提高页面加载速度

    // 当资源文件小于10kb就会通过base64编码方式引入资源;大于10kb的话,url-loader会在内部调用file-loader引入资源,所以使用了以下配置项,必须安装file-loader
    {
      test: /.jpg/,
      use: [
        {
          loader: 'url-loader',
          options: {
            limit: 10 * 1024  // 10kb
          }
        }
      ]
    }
    

    代码检查类

    加载资源的方式

    ES module 的 import

    遵循Commonjs标准的require函数

    遵循AMD标准的define和require函数

    loader加载非js的资源

    css中的@import指令和url函数

    如下图例子,css中通过@import指令引入heading.css样式文件,heading.css中通过url函数引入背景图片。

    /* main.css */
    @import './heading.css';
    body {
      font-size: 20px;
    }
    /* heading.css */
    .heading {
      background-color: gray;
      background-image: url(./avatar.jpg);
    }
    
    // webpack.config.js
    module: {
      rules: [
        ...
        {
          test: /.css$/,
          use: ["style-loader", "css-loader"],
        },
        {
          test: /.jpg$/,
          use: [
            {
              loader: "url-loader",
              options: {
                limit: 10 * 1024, // 10kb
              }
            }
          ]
        }
      ]
    }
    

    html中的资源加载

    // main.js
    import footerHtml from './footer.html'
    document.write(footerHtml);
    
    <!-- footer.html -->
    <footer>
      <a href="./wall.jpg">跳转wall图片</a>
      <img src="./avatar.jpg">
    </footer>
    
    // webpack.config.js 
    
    // html-loader v0.5.5版本及以下
    {
      test: /.html$/,
      use: {
        loader: "html-loader",
        options: {
          attrs: ["img:src", "a:href"] // 默认为 attrs: ['img:src']
        }
      }
    }
    
    // html-loader v1.0.0版本以上
    {
      test: /.html$/,
      use: {
        loader: "html-loader",
        options: {
          attributes: {
            list: [
              // All default supported tags and attributes
              "...",
              {
                tag: "a",
                attribute: "href",
                type: "src",
              }
            ]
          }
        }
      }
    }
    

    自定义loader

    1、对于同一份资源,可以采用多个loader处理 1、每个loader都必须导出一个函数 2、经过多个loader处理后,最后返回的结果必须是一段标准的JavaScript代码

    实现1

    // webpack.config.js
    const path = require('path')
    module.exports = {
      mode: 'none',
      entry: './src/main.js',
      output: {
        filename: 'bundle.js',
        path: path.join(__dirname, 'dist'),
        publicPath: 'dist/'
      },
      module: {
        rules: [
          {
            test: /.md$/,
            use: {
              loader: './md-loader.js'
            }
          }
        ]
      }
    }
    // main.js
    import about from './about.md'
    console.log(about)
    // about.md
    ## md-loader
    

    md-loader.js

    // 写法1
    module.exports = source => {
      return source
    }
    // 写法2
    module.exports = source => {
      return `console.log("md-loader")`
    }
    // 正确写法,CommonJS
    module.exports = source => {
      return `module.exports = ${JSON.stringify(source)}`
    }
    // 正确写法,ES Module
    module.exports = source => {
      return `export default ${JSON.stringify(source)}`
    }
    

    采用第一种写法,直接在函数返回source,会提示打包错误:"You may need an additional loader to handle the result of these loaders."。因为最终结果必须是标准的javascript代码
    前端模块化-webpack
    打包后的bundle.js 前端模块化-webpack 采用第二种写法,在函数内返回javascript代码的结果如下: 前端模块化-webpack
    可以看到"console.log(1)"被直接放到函数内
    由于我们需要把md文件的内容模块化导出,所以导出的内容需要采用CommonJS或ES Module的标准返回,并且为了能够把md文件内容转化为html,引入"marked"模块进行处理。

    // CommonJS
    const marked = require('marked')
    module.exports = source => {
      const html = marked(source)
      return `module.exports = ${JSON.stringify(html)}`
    }
    

    输出
    前端模块化-webpack

    // ES Module
    const marked = require('marked')
    module.exports = source => {
      const html = marked(source)
      return `export default ${JSON.stringify(html)}`
    }
    

    输出
    前端模块化-webpack

    实现2

    通过md-loader将md文件转换成html,再通过html-loader处理,生成标准的javascript代码 前端模块化-webpack

    // webpack.config.js
    const path = require('path')
    module.exports = {
      mode: "none",
      entry: "./src/main.js",
      output: {
        filename: "bundle.js",
        path: path.join(__dirname, "dist"),
        publicPath: "dist/",
      },
      module: {
        rules: [
          {
            test: /.md$/,
            use: ["html-loader", "./md-loader.js"]
          },
        ],
      },
    };
    // md-loader.js
    const marked = require('marked')
    module.exports = source => {
      const html = marked(source)
      // 直接返回html给下一个loader(html-loader)
      return html;
    }
    

    输出
    前端模块化-webpack

    plugin

    clean-webpack-plugin

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

    html-webpack-plugin

    硬编码对应的问题

    前端模块化-webpack

    • 发布代码需要同时发布根目录下的index.html和dist目录中的资源,相对麻烦
    • 需要手动维护index.html中资源引用路径(webpack bundle文件名中包含的哈希值随着编译而发生变化)

    单页面

    <!-- index.html -->
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <!-- 使用lodash模板语法读取变量值 -->
      <title><%= htmlWebpackPlugin.options.title %></title>
    </head>
    <body>
      <!-- 此处并不需要引入main.js,Html-webpack-plugin只是把index.html当做一个模板文件,不会根据它分析文件依赖关系 -->
      <!-- <script src="src/main.js" type="module"></script> -->
    </body>
    </html>
    
    // webpack.config.js
    const path = require('path')
    const { CleanWebpackPlugin } = require('clean-webpack-plugin')
    +const HtmlWebpackPlugin = require('html-webpack-plugin')
    module.exports = {
      mode: "none",
      entry: "./src/main.js",
      output: {
        filename: "bundle.js",
        path: path.join(__dirname, "dist")
    -    publicPath: "dist/",
      },
      module: {
        rules: [
          {
            test: /.html$/,
    +       exclude: [require.resolve("./index.html")],  // 需要排除掉index.html,否则lodash模板语法不会生效
            use: {
              loader: "html-loader",
              options: {
                attributes: {
                  list: [
                    // All default supported tags and attributes
                    "...",
                    {
                      tag: "a",
                      attribute: "href",
                      type: "src",
                    },
                  ],
                },
              },
            },
          },
          {
            test: /.css$/,
            use: ["style-loader", "css-loader"],
          },
          {
            test: /.jpg$/,
            use: [
              {
                loader: "url-loader",
                options: {
                  limit: 10 * 1024, // 10kb
                }
              }
            ]
          }
        ]
      },
      plugins: [
        new CleanWebpackPlugin(),
    +   new HtmlWebpackPlugin({
    +      title: "网页标题",
    +      meta: {
    +        viewport: "width=device-width",
    +      },
    +      template: "./index.html",
    +    }),
      ]
    }
    

    多页面

    plugins: [
      new CleanWebpackPlugin(),
      new HtmlWebpackPlugin({
        title: "网页标题",
        meta: {
          viewport: "width=device-width",
        },
        template: "./index.html",
      }),
      new HtmlWebpackPlugin({
        filename: 'about.html'
      })
    ]
    

    思考题

    有了解过 webpack 源码吗?

    webpack import 打包后的结果是怎样的?

    webpack 用过吗?打包原理是怎么样的?用过什么打包工具?

    webpack插件和loader的区别

    webpack性能优化

    loader实现机制和原理

    有没有看过一些源码,整理的webpack项目有什么难点,怎么进行优化的


    起源地下载网 » 前端模块化-webpack

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元