node 第二十一天 webpack 初见

  1. 为什么需要学习(了解)webpack
    webpack是前端工程化的基石,webpack又是基于node进行文件打包bundle,所以作为前端起手学习node服务端开发,同时学习webpack是很有必要的。
    随着vite的出现,vue这一脉可能也许不再需要学习webpack了,但是需要知道的是,打包一定是前端工程化绕不开的一个概念,如果是一个足够了解webpack的开发者,日后再学习任何一款前端构建工具都将事半功倍。
    但是webpack本身却是是复杂的。真要深入学习付出是必不可少的。
    经过基础学习之后能够具备对问题顺藤摸瓜的能力,这是基础要求。

  2. webpack概念

    本质上,webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。

  3. webpack核心配置项

    • webpack.common.js 基本配置项 入口(entry), 出口(output), 插件(plugins),模块打包(loader)
      const path = require('path');
      const HtmlWebpackPlugin = require('html-webpack-plugin');
      const webpack = require('webpack');
      const MyPlugin = require('./myPlugin');
      
      module.exports = {
        // 入口 可多个
        entry: './src/main.js',
        // 出口 可多个
        output: {
          path: path.resolve(__dirname, 'dist'),
          filename: 'build.js'
        },
        // 插件
        plugins: [
          new webpack.DefinePlugin({
            VERSION: JSON.stringify('1.0.0')
          }),
          new HtmlWebpackPlugin({ template: './public/index.html', title: 'webpack app' }),
          new MyPlugin()
        ],
        // 模块loader
        module: {
          rules: [
            {
              test: /\.css$/i,
              use: ['style-loader', 'css-loader', './myLoader']
            }
          ]
        }
      };
      
      
    • webpack.dev.js 开发环境配置项 代理服务器(devServer) 调试工具(devtool)
      const { merge } = require('webpack-merge');
      const path = require('path');
      const common = require('./webpack.common.js');
      const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
      
      module.exports = merge(common, {
        plugins: [
          new BundleAnalyzerPlugin({
            analyzerPort: 8888,
            openAnalyzer: false
          })
        ],
        // 模式
        mode: 'development',
        // devServer
        devServer: {
          static: {
            // 告诉服务器从哪里提供内容。只有在你希望提供静态文件时才需要这样做。static.publicPath 将会被用来决定应该从哪里提供 bundle,并具有优先级。
            publicPath: '/',
            directory: path.join(__dirname, 'public')
          },
          host: 'localhost',
          port: 8080,
          open: true
        },
        // source-map 会在webpack打包生成的文件模块的末端 加上 //# sourceURL=
        // 映射source-map
        devtool: 'inline-source-map'
      });
      
    • webpack.prod.js 生产环境配置项 externals(打包剔除优化)
      const { merge } = require('webpack-merge');
      const common = require('./webpack.common.js');
      const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
      const { CleanWebpackPlugin } = require('clean-webpack-plugin');
      
      module.exports = merge(common, {
        plugins: [
          new CleanWebpackPlugin(),
          new BundleAnalyzerPlugin({
            analyzerPort: 1055,
            openAnalyzer: false
          })
        ],
        // 模式
        mode: 'production',
        // externals key: value
        // key和 import jQ from 'jquery'; 中的 'jquery' 一样
        // value 用于替换 import jQ from 'jquery' 中的jQ
        // 所以 value 必须和cdn引用暴露的window变量一样
        externals: {
          jquery: 'jQuery'
        }
      });
      
  4. main.js 顺着main.js我们往下看

    import './style.css';
    
    import jQ from 'jquery';
    
    const str = 'hello webpack';
    // 再webpack中
    // 告知 webpack 将 process.env.NODE_ENV 设置为一个给定字符串。
    // 如果 optimization.nodeEnv 不是 false,则会使用 DefinePlugin,optimization.nodeEnv 默认值取决于 mode,
    // 如果为 falsy 值,则会回退到 "production"。
    console.log(process.env.NODE_ENV);
    //打包常量直接替换为 console.log('hello webpack');
    console.log(str);
    //生产环境用cdn
    console.log(jQ);
    //webpack.DefinePlugin
    console.log(VERSION);
    
    // 开启 devtool: 'inline-source-map' 方便调试
    // console.log(VERSION.t.t);
    
  5. 实现js文件中引入css
    因为在webpack.common.js中配置了css模块的loader,这样webpack就能知道怎么去处理对应的文件,以及处理之后给js暴露一个什么样的对象

  6. 生产环境不将jquery打包,改用cdn引入
    因为在webpack.prod.js中配置了打包剔除优化(externals),结合使用插件HtmlWebpackPlugin 结合 ejs语法, 在html模板中实现生产环境使用cdn引入jquery,当然此处还涉及了如何判断开发环境和生产环境,用到了一个node进程对象变量process.env.NODE_ENV 默认情况取决于webpack配置项mode的值
    html模板如下

    DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title><%= htmlWebpackPlugin.options.title %>title>
        <% if (process.env.NODE_ENV === 'production' ) { %>
        <script src="https://code.jquery.com/jquery-3.7.1.min.js">script>
        <% } %>
      head>
      <body>
        <h1>hello webpack serverh1>
      body>
    html>
    
  7. 使用DefinePlugin 在 编译时 将代码中的变量替换为其他值或表达式
    这里你也可以用来区分开发环境和生产环境而不是使用process.env.NODE_ENV , 在main.js中我们输出了一个被定义为字符串1.0.0的VERSION,console.log(VERSION); ==> console.log('1.0.0');

  8. 实现MyLoader MyPlugincmd控制台打印MyLoader… MyPlugin… 自定义规则需要结合文档

    module.exports = function (source) {
      const content = source;
      console.log('MyLoader...');
      return content;
    };
    //loader 从右到左(或从下到上)地取值(evaluate)/执行(execute)
    //盲猜源码用了pop()
    
    module.exports = class MyPlugin {
      apply(compiler) {
        // 找到合适的事件钩子,实现自己的插件功能
        compiler.hooks.emit.tap('MyPlugin', () => {
          // compilation: 当前打包构建流程的上下文
          console.log('MyPlugin...');
        });
      }
    };
    

你可能感兴趣的:(webpack,前端,node.js)