chenqunfeng / Blog

个人技术记录博客
6 stars 1 forks source link

Webpack2文档梳理 #9

Open chenqunfeng opened 7 years ago

chenqunfeng commented 7 years ago

前言

以下梳理是基于webpack2.6.1版本的梳理。基本所有示例代码都来自官网。英文文档中文文档

Tree shaking

Tree shaking是一个术语,通常用来描述移除Javascript上下文中无用代码这个过程,更准确来说的话,就是能按需引用代码(不知道能不能按需引用jquery等一些库文件的代码,有待检测),而这个概念实际上兴起于rollup。 官方例子

代码分离

Code Splitting - CSS

extract-text-webpack-plugin

Code Splitting - Libraries

在应用里面,可能会有很多场景存在公共依赖,如第三方类库、公共模块等,而这些公共依赖一般不会频繁改动。所以,我们可以将它们提取成一个vendor文件,利用浏览器缓存机制可以让vendor文件长时间缓存在浏览器上。 为了完成这个目的,我们可以使用一个插件,CommonsChunkPlugin。 webpack.config.js

// 官方例子
var webpack = require('webpack');
var path = require('path');

module.exports = function(env) {
    return {
        entry: {
            main: './index.js',
            // 支持数组形式,可以定制vendor包含的模块,如[ 'jquery', 'moment' ]
            vendor: 'moment'
        },
        output: {
            filename: '[name].[chunkhash].js',
            path: path.resolve(__dirname, 'dist')
        },
        plugins: [
            new webpack.optimize.CommonsChunkPlugin({
                // 默认只提取entry中vendor声明的模块,这里只提取moment模块
                name: 'vendor',
                // 以下配置会提取项目文件中import了node_modules下的模块
                //minChunks: function(module) {
                //    return module.context && module.context.indexOf('node_modules') !== -1;
                //}
            })
        ]
    }
}

虽然看似公共依赖都被我们打包到vendor中,但是我们可以发现按照以上的配置vendor文件的hash会随着每一次编译而变化,也就起不到能长久保留在浏览器缓存中的目的了。 究其原因,是因为在每一次构建的时候,webpack都会生成运行时的代码来帮助完成webpack的工作。当只有一个单入口的时候,这份运行时的代码会被打包在这个入口文件内,而当有vendor入口时,则会打包在vendor文件中。为了避免这个问题,我们需要将这份运行时的代码单独提取为一份manifest文件。 webpack.config.js

// 官方例子
var webpack = require('webpack');
var path = require('path');

module.exports = function(env) {
    return {
        entry: {
            main: './index.js',
            vendor: 'moment'
        },
        output: {
            filename: '[name].[chunkhash].js',
            path: path.resolve(__dirname, 'dist')
        },
        plugins: [
            new webpack.optimize.CommonsChunkPlugin({
                names: ['vendor', 'manifest'] // Specify the common bundle's name.
            })
        ]
    }
};

Code Splitting - Async

我们都知道可以在文件的顶部引入依赖,但是这一股脑将一个文件的所有依赖全部前置也并不是一个明智的做法,很多时候,我们希望能够动态引入某些依赖。

说在前面

配合babel的动态引入

command line

npm install --save-dev babel-core babel-loader babel-preset-es2015
// for this example
npm install --save moment

example code

function determineDate() {
  import('moment')
    .then(moment => moment().format('LLLL'))
    .then(str => console.log(str))
    .catch(err => console.log('Failed to load moment', err));
}

determineDate();

webpack.config.js

module.exports = {
  entry: './index-es2015.js',
  output: {
    filename: 'dist.js',
  },
  module: {
    rules: [{
      test: /\.js$/,
      exclude: /(node_modules)/,
      use: [{
        loader: 'babel-loader',
        options: {
          presets: [['es2015', {modules: false}]]
        }
      }]
    }]
  }
};

ES2017动态引入

command line

npm install --save-dev babel-plugin-transform-async-to-generator babel-plugin-transform-regenerator babel-plugin-transform-runtime

example code

async function determineDate() {
  const moment = await import('moment');
  return moment().format('LLLL');
}

determineDate().then(str => console.log(str));

webpack.config.js

module.exports = {
  entry: './index-es2017.js',
  output: {
    filename: 'dist.js',
  },
  module: {
    rules: [{
      test: /\.js$/,
      exclude: /(node_modules)/,
      use: [{
        loader: 'babel-loader',
        options: {
          presets: [['es2015', {modules: false}]],
          plugins: [
            'transform-async-to-generator',
            'transform-regenerator',
            'transform-runtime'
          ]
        }
      }]
    }]
  }
};

Magic comment

webpackMode: 动态引入的模块的模式 "lazy": 默认行为,动态引入的请求按独个请求引入。 "lazy-once": 仅适用于带表达式的动态引入。为所有的请求生成单个块。第一次请求会 "eager": 所有文件都包含在当前块中,不需要网络请求来加载文件。 webpackChunkName: 动态引入的模块的命名 import(/*webpackMode: "lazy" webpackChunkName: "my-chunk-name" */ 'module')

生产环境构建

Source Maps

在生产环境中推荐配置source map,因为该配置项可以在测试环境中,可以将打包成bundle的文件,一份份生成原本的独立文件模块。 建议直接使用以下选项,更多配置可看。 devtool: "source-map"

Node环境变量

缓存

[hash]:根据依赖生成hash,任何文件更新之后构建就会更新所有文件名。 [chunkhash]:根据文件内容生成一个唯一的hash。 [contenthash]:css

在webpack.config.js使用es6语法