webpack:使用笔记

原理

模块化 是 webpack 实现的前提和核心的理念,webpack处理任何资源都是将其作为模块来操作。

webpack打包核心流程可以概括为:分析配置,解析代码,查找依赖,生成模块,打包文件。

webpack打包流程执行原理示例:

/* 初始化配置:
    运行打包shell命令行,传入打包参数
    读取打包配置文件
    对配置进行处理,合并生成最终配置
*/
// ...默认使用webpack.config.js的webpack配置
const webpackConfig = require('webpack.config.js');

/* 实例化编译器:
    使用合成的配置初始化Compiler对象实例
    加载配置中所需插件
*/
// ...默认使用本地webpack-cli,引入webpack模块
const webpack = require('webpack');
// 传入webpack配置,运行webpack模块,返回compiler实例
const compiler = webpack(webpackConfig);

/* 执行编译:
    运行Compiler.run()方法,从entry配置项指定的入口文件开始执行编译,
    使用指定loader对相应文件进行解析,分析模块依赖,
    递归执行此操作,最终所有入口文件依赖的所有模块全部解析和编译完成,
    所有模块编译后的内容和相互依赖关系确定。
*/
// 开始执行编译 
compiler.run((err, stats)=>{
  // stats为compiler.getStats()方法(内部调用lib/Stats.js类创建实例)返回的实例对象
  /* stats重要属性:
    entries
    chunks
    modules
    assets:{}
  */

});

/* 输出模块:
    根据依赖关系和模块体积,将模块进行组合、拆分为多个chunk,
    将每个chunk加入文件生成列表,准备生成资源。
    此步骤是输出内容最后一个可修改阶段。
*/

/* 生成文件:
    将文件生成列表按照指定路径和名称写入文件系统。
*/







概念

  • Entry:webpack构建起始文件,代码依赖关系起点。可以设置多入口,生成多套依赖关系。
  • Output:webpack构建文件的存放目录和命名。
  • Loaders:webpack通过loader将js以外各类资源读取为可处理模块对象。
  • Plugins:对webpack功能进行增强和补充,帮助webpack实现打包性能优化,打包体积优化,打包分析等功能。
  • Chunks:webpack对代码模块化进行打包优化的重要方式,如复用模块分离去重,第三方模块分离缓存,异步模块分离加载等。

配置

​
const path = require('path');

module.exports = {
​  // 环境标识: development / production / ...
  // 如果执行的shell脚本命令包含环境标识则优先使用shell参数
  mode: 'development',
  /* 调试工具:是否 和 如何 生成 source map
    source-map:生成map文件,标识异常代码对应源文件中的行和列
    eval-source-map:不生成map文件,标识 行 和 列
    cheap-module-source-map:生成map文件,标识 行
    cheap-module-eval-source-map:不生成map文件,标识 行
    开启调试工具可能会影响
  */
  devtool: 'eval-cheap-source-map',
  // 入口文件:打包起始文件,依赖图起点
  entry: './src/index.js',
  // 输出配置
  output: {
    // 打包文件输出目录
    path: path.resolve(__dirname, './dist'),
    // 打包输出文件名
    filename: '[name]_[hash:8].js',
    // 打包依赖文件名
    chunkFilename: '[name]_[contenthash:8].js',
    // 外部资源路径
    publicPath: path.resolve(__dirname, './dist'), // 相对于服务器根目录
    // publicPath: "./dist/", // 相对于模板文件 app.html
    // publicPath: 'https://cdn.example.com/assets/', // CDN(总是 HTTPS 协议)
    // publicPath: "//cdn.clound.com/dist/", // CDN(协议相同)
  },
  // 模块解析配置
  module: {
    /* 指定不需要解析的模块:对于第三方库或已经处理过的静态资源,
      不需要被解析,提高打包效率
      注意:此配置将排除对指定文件进行模块解析处理,
      直接使用模块源代码进行打包,减少的webpack的工作量,
      不会减少打包体积,因为指定文件不会被排除打包
      */
    noParse: /jquery/,
    // loader配置
    rules: [
      {
        test: /\.(js|jsx)$/,
        /* include :指定需要执行的目录
          exclude :指定不需要执行的目录
          对于node_modules或已经处理过的静态资源,不需要再次执行babel,
          通过配置exclude排除以提升效率,
          注意:此配置将排除对指定文件使用当前loader进行处理,
          减少的webpack的工作量,不会减少打包体积,
          因为指定文件不会被排除打包
        */
        exclude: /node_modules/,
        // loader:"babel-loader",
        // options: { presets: ["@babel/env"] },
        // 多个 loader 用 use 数组按执行顺序倒叙加载
        use: [
          'thread-loader', // 使用多线程loader
          'cache-loader', // 将编译结果缓存到磁盘,再次构建时如果文件没有发生变化则会直接使用缓存
          {
            loader: 'babel-loader',
            options: { presets: ['@babel/env'] },
          },
        ],
      },
      {
        test: /\.css$/,

        use: [
          'cache-loader', // 将编译结果缓存到磁盘,再次构建时如果文件没有发生变化则会直接使用缓存
          // process.env.NODE_ENV === "development" ?  "style-loader" :
          MiniCssExtractPlugin.loader,
          // "css-loader?modules&localIdentName=[name]_[local]_[hash:base64:4]&importLoaders=1", // 字符串形式
          {
            // 对象形式
            loader: 'css-loader',
            options: {
              importLoaders: 2, // 在 css-loader 前应用的 loader 的数量
              modules: true, // 开启css-modules
              localIdentName: '[name]_[local]_[md5:contenthash:base64:4]', // 命名规则
            },
          },
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  // 使用最新 css属性, 该插件已经包含autoprefixer(根据 Can I Use 中各大厂商兼容性自动添加前缀)
                  'postcss-preset-env',
                  'cssnano', // 压缩
                  'stylelint', // 格式化
                  /* 支持字符串 数组 CommonJS包 函数,详见postcss配置
                    ["postcss-short", { prefix: "x" }],
                    require.resolve("my-postcss-plugin"),
                    myOtherPostcssPlugin({ myOption: true }),
                    */
                ],
              },
            },
          },
        ],
      },
      {
        test: /\.less$/,
        use: [
          'cache-loader',
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              importLoaders: 2,
              modules: true,
              localIdentName: '[name]_[local]_[md5:contenthash:base64:4]',
            },
          },
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: ['postcss-preset-env', 'cssnano', 'stylelint'],
              },
            },
          },
          'less-loader',
        ],
      },
    ],
  },
  // 插件配置
  plugins: [
    new CleanWebpackPlugin(), // 每次打包自动清理上次输出文件
    /* new CopyWebpackPlugin( {
      patterns: [
        // 复制静态文件
        { from: path.resolve( __dirname, './static/fonts' ) },
      ]
    }), */
    /* 指定排除打包的文件,减小打包体积
      打包时将 moment 引入.locale 语言包排除
      在项目代码中使用moment时,需要手动引用中文包 import "moment/locale/zh-cn"
      否则无法设置语言为中文 moment.locale('zh-cn')
      这样相当于将于只打包了语言包中的中文部分
    */
    new webpack.IgnorePlugin(/\.\/locale/, /moment/),
    new MiniCssExtractPlugin({
      // 将css分离成单独文件,不依赖于 JS
      filename: '[name]_[contenthash:8].css',
      chunkFilename: '[name]_[contenthash:8].css',
    }),
    new HtmlWebpackPlugin({
      // 输出 html文件,每一个HtmlWebpackPlugin实例对应一个页面,实现多页面打包
      template: path.resolve(__dirname, './src/index.html'), // 入口模板文件
      // templateContent:'<div id="root"></div>',// 入口模板内容 不能和模板文件同时配置
      filename: 'index.html',
    }),
    new webpack.BannerPlugin('版权声明,将被插入到所有打包生成的js文件开头'),
    // new BundleAnalyzerPlugin() // 打包体积分析
  ],

  resolve: {
    /* 指定模块路径:默认['node_modules']
      从当前目录 ./node_modules 查找,到上级目录 ../node_modules,最后到根目录(即 npm 查找包的规则)
      直接指定项目根目录,可以减少查找耗时
      */
    modules: [path.resolve(__dirname, 'node_modules')],
    /* 指定扩展名:默认['js', 'json']
      导入模块没有后缀时,Webpack 会使用extensions后缀列表尝试匹配文件,
      如:require('./data') 时 ,Webpack 会先尝试寻找 data.js,没有再去找 data.json;
      列表越长,或者正确的后缀越往后,尝试的次数就会越多。
      频率出现高的文件后缀优先放在前面。
      列表尽可能的少,例如只有 3 个:js、jsx、json。
      书写导入语句时,尽量写上后缀名。
    */
    extensions: ['*', '.js', '.jsx'],
  },

  /**
   * 监听变化:代码变更自动打包
   * devServer将打包结果保存在内存中,不创建打包文件
   * 开启监听自动打包可以查看实时产生的打包文件
   */
  // watch: true,
  /**
   * 监听选项
   */
  // watchOptions: {
  //   poll: 10, // 每秒检测变化次数
  //   aggregateTimeout: 1000, // 用于防抖的超时时间 ms
  //   ignored: /node_modules/, // 忽略监听的目录
  // },

  // optimization: {
  //   splitChunks: {
  //     cacheGroups: {
  //       common: {
  //         chunks: 'initial', // 'async'
  //         minSize: 1,
  //         minChunks: 1,
  //       },
  //       vendor: {
  //         priority: 1,
  //         test: /node_modules/,
  //         chunks: 'initial', // 'async'
  //         minSize: 1,
  //         minChunks: 1,
  //       },
  //     },
  //   },
  //   minimizer: [
  //     new TerserPlugin({
  //       // webpack默认代码压缩插件为uglifyjs
  //       // TerserPlugin可以实现多进程并行压缩
  //       parallel: 4, // 开启多进程并行压缩
  //     }),
  //   ],
  // },
};

// module.exports = NewSpeedMeasurePlugin.wrap(config); // 打包速度分析打包
module.exports = config; //打包速度分析打包

安装node

初始化项目

npm init -y

安装webpack到项目

npm install webpack webpack-cli --save-dev

配置package.json 文件

设置private为true,移除 main 入口

  {
    "name": "webpack-demo",
    "version": "1.0.0",
    "description": "",
    "private": true,    //配置private为true
    //"main": "index.js",//并且移除 main 入口
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
      "webpack": "^4.0.1",
      "webpack-cli": "^2.0.9"
    },
    "dependencies": {}
  }

安装jquery到项目

npm install --save jquery

安装一个用于生产环境的安装包,应使用 npm install --save

安装一个用于开发环境的安装包(例如,linter, 测试库等),应使用 npm install --save-dev

详见 npm 文档 

调整目录结构

src用于存放项目源代码,dist用于存放webpack构建后输出的优化后的代码(最终将在浏览器中加载使用的)

  webpack-demo
  |- package.json
  |- /dist
    |- index.html
  |- /src
    |- index.js

在index.js中引入jquery

import $ from 'jquery'

编辑index.html文件

 <!doctype html>
  <html>
   <head>
     <title>webpack</title>
   </head>
   <body>

   <script src="bundle.js"></script>
   </body>
  </html>

执行npx命令

npx webpack

此时访问index.html使用的已经是webpack输出的项目文件了

创建配置文件webpack.config.js 

  webpack-demo
  |- package.json
  |- webpack.config.js 
  |- /dist
    |- index.html
  |- /src
    |- index.js

编辑配置文件webpack.config.js 

const path = require('path');

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

使用npx命令

npx webpack --config webpack.config.js

此时访问index.html使用的是webpack按照webpack.config.js中的配置输出的项目文件

注意,在 windows 中通过路径调用 webpack 时,必须使用反斜线。如 node_modules\.bin\webpack --config webpack.config.js

如果 webpack.config.js 存在,则 webpack 命令将默认选择使用它。我们在这里使用 --config 选项只是向你表明,可以传递任何名称的配置文件。这对于需要拆分成多个文件的复杂配置是非常有用。

使用NPM 脚本

修改package.json文件

  {
    "name": "webpack-demo",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
      "build": "webpack" //增加build命令,设置为执行webpack
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
      "webpack": "^4.0.1",
      "webpack-cli": "^2.0.9",
      "lodash": "^4.17.5"
    }
  }

调用新增的脚本命令

npm run build

通过向 npm run build 命令和你的参数之间添加两个中横线,可以将自定义参数传递给 webpack,例如:npm run build -- --colors

加载CSS

安装 style-loader 和 css-loader

npm install --save-dev style-loader css-loader

修改webpack.config.js文件

  const path = require('path');

  module.exports = {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
    },
    module: {  //增加module配置
      rules: [
        {
          test: /\.css$/,
          use: [
            'style-loader',
            'css-loader'
          ]
        }
      ]
    }
  };

webpack 根据正则表达式,来确定应该查找哪些文件,并将其提供给指定的 loader。在这种情况下,以 .css 结尾的全部文件,都将被提供给 style-loader 和 css-loader

创建style.css文件

webpack-demo
  |- package.json
  |- webpack.config.js
  |- /dist
    |- bundle.js
    |- index.html
  |- /src
    |- style.css //添加样式文件到源代码目录
    |- index.js
  |- /node_modules

编辑index.js文件

import $ from 'jquery';
import './style.css'; //引入样式文件

引入平级目录下文件要在路径开头写 ./ ,不能直接引用

使用npm脚本

npm run build

此时访问index.html已经具备了style.css文件中的样式

这时的样式是通过js添加在index.html中一个style标签来实现的,在生产环境中多数情况下需要使用ExtractTextWebpackPlugin把使用 CSS文件分离,以便节省加载时间。此外,现有的 loader 可以支持postcsssass 和 less等任何CSS 处理器风格 。

加载图片 字体 数据

安装 file-loader (图片 和 字体)csv-loader ( CSV和TSV) xml-loader(XML),NodeJS内置支持JSON格式数据

npm install --save-dev file-loader
npm install --save-dev csv-loader xml-loader

编辑webpack.config.js文件

  const path = require('path');

  module.exports = {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
    },
    module: {
      rules: [
        {
          test: /\.css$/,
          use: [
            'style-loader',
            'css-loader'
          ]
        },  //在module中增加file-loader处理规则
        {
          test: /\.(png|svg|jpg|gif)$/,
          use: [
            'file-loader'
          ]
        },
        {
          test: /\.(woff|woff2|eot|ttf|otf)$/,
          use: [
            'file-loader'
          ]
        },
        {
          test: /\.(csv|tsv)$/,
          use: [
            'csv-loader'
          ]
        },
        {
          test: /\.xml$/,
          use: [
            'xml-loader'
          ]
        }
      ]
    }
  };

在项目目录增加相关资源文件

在index.js文件中引入

import $ from 'jquery';
import './style.css'; 
import Icon from './icon.png';
import DataXML from './data.xml';
import DataJSON from './data.json';//NodeJS内置支持JSON格式数据

当使用 import Icon from './icon.png'时,该图像将被处理并添加到 output 目录,Icon 变量将包含该图像在处理后的最终 url。

当使用 css-loader 时,loader会以相同的方式处理 CSS 中的 url('./icon.png') ,将 './icon.png' 路径,替换为输出目录中图像的最终url。

当使用html-loader时,loader会以相同的方式处理HTML中的<img src="./icon.png" />,将 './icon.png' 路径,替换为输出目录中图像的最终url。

此外,还以通过 image-webpack-loader 和 url-loader 来压缩和优化图像 。

在使用 d3 等工具来实现某些数据可视化时,预加载数据会非常有用。我们可以不用再发送 ajax 请求,然后于运行时解析数据,而是在构建过程中将其提前载入并打包到模块中,以便浏览器加载模块后,可以立即从模块中解析数据。

管理输出-重构

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值