我的webpack,持续更新......

来源:互联网 发布:旺旺名是淘宝名吗 编辑:程序博客网 时间:2024/05/23 00:21

压缩js

使用自带的webpack.optimize.UglifyJsPlugin

const webpack = require('webpack');module.exports = function(env) {  return {    entry: {      main: './index.js',    },    output: {      filename: '[chunkhash].[name].js',      path: path.resolve(__dirname, 'dist')    },    plugins: [      new webpack.optimize.UglifyJsPlugin({        compress: {          warnings: false,          drop_console: false,        }      }),    ]  }}

分离css

1、安装extract-text-webpack-plugin插件

npm i --save-dev extract-text-webpack-plugin@beta

2、在webpack.config.js中使用这个插件

var ExtractTextPlugin = require('extract-text-webpack-plugin');module.exports = function () {  return {    entry: './index.js',    output: {      path: './dist',      filename: 'bundle.js'    },    module: {      rules: [{        test: /\.css$/,        exclude: /node_modules/,        use: ExtractTextPlugin.extract({            loader: 'css-loader'        })      }]    },    // devtool: 'source-map',    plugins: [      new ExtractTextPlugin({ filename: 'bundle.css', disable: false, allChunks: true })    ]  }}

提取公共文件

使用CommonsChunkPlugin的几种方式:
https://webpack.js.org/plugins/commons-chunk-plugin/#components/sidebar/sidebar.jsx
以下内容参考自:https://doc.webpack-china.org/guides/code-splitting-libraries/#-vendor-chunk

但是,如果我们改变应用的代码并且再次运行 webpack,可以看到 vendor 文件的 hash 改变了。即使我们把 vendor 和 main 的 bundle 分开了,也会发现 vendor bundle 会随着应用代码改变。
这意味着我们任然无法从浏览器缓存机制中受益,因为 vendor 的 hash 在每次构建中都会改变,浏览器也必须重新加载文件。

这里的问题在于,每次构建时,webpack 生成了一些 webpack runtime 代码,用来帮助 webpack完成其工作。当只有一个 bundle 的时候,runtime 代码驻留在其中。但是当生成多个 bundle的时候,运行时代码被提取到了公共模块中,在这里就是 vendor 文件。

为了防止这种情况,我们需要将运行时代码提取到一个单独的 manifest 文件中。尽管我们又创建了另一个 bundle,其开销也被我们在 vendor 文件的长期缓存中获得的好处所抵消。

// index.jsvar moment = require('moment');var path = require('path');console.log(moment().format(), 11122334455);console.log(path.resolve(__dirname, '/dist'));console.log(path.join(__dirname, '/dist'));
// webpack.config.jsvar path = require('path');var webpack = require('webpack');var HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = function(env) {  return {    entry: {      main: './index.js',      vendor: ['moment', 'path'] // 提取moment,path模块到wendor文件    },    output: {      filename: '[name].js', // 原来是[chunkhash].[name].js      path: path.resolve(__dirname, 'dist')    },    plugins: [      new webpack.optimize.CommonsChunkPlugin({        // name: 'vendor_modules',        // minChunks: function (module) {        //    // 该配置假定你引入的 vendor 存在于 node_modules 目录中        //    return module.context && module.context.indexOf('node_modules') !== -1;        // }        names: ['vendor', 'manifest']      }),      new HtmlWebpackPlugin({        template: './index.html' //使用当前目录(根目录)下的index.html      })    ]  }}

使用webpack打包后,dist目录命令有(xxxxx表示hash值)

index.htmlxxxxx.main.jsxxxxx.manifest.js //webpack runtime 代码xxxxx.vendor.js

修改index.js代码,再次打包后,只会生更新manifest.js和main.js。而最大的共同包vendor.js是不会变得。通过hash值可以看到。这样vendor.js就可以缓存到浏览器了。

提取公共文件+

https://doc.webpack-china.org/guides/caching/
为了最小化生成的文件大小,webpack 使用标识符而不是模块名称。在编译期间,生成标识符并映射到块文件名,然后放入一个名为 chunk manifest 的 JavaScript 对象中。

为了生成保存在构建中的标识符,webpack 提供了 NamedModulesPlugin(推荐用于开发模式)和HashedModuleIdsPlugin(推荐用于生产模式)这两个插件。

然后将 chunk manifest(与引导/运行时代码一起)放入 entry chunk,这对 webpack 打包的代码工作是至关重要的。

改变其他文件时mainfest.js改变

这个问题和以前一样:每当我们改变代码的任何部分时,即使它的内容的其余部分没有改变,都会更新我们的入口块以便包含新的映射(manifest)。 这反过来,将产生一个新的哈希值并且使长效缓存失效。

使用ChunkManifestWebpackPlugin

要解决这个问题,我们应该使用 ChunkManifestWebpackPlugin,它会将 manifest 提取到一个单独的 JSON 文件中。 这将用一个 webpack runtime 的变量替换掉chunk manifest。 但我们可以做得更好;我们可以使用 CommonsChunkPlugin 将运行时提取到一个单独的入口起点(entry)中去。这里是一个更新后的 webpack.config.js,将生成我们的构建目录中的 manifest 和 runtime 文件:

// webpack.config.jsvar ChunkManifestPlugin = require("chunk-manifest-webpack-plugin"); module.exports = {   /*...*/   plugins: [     /*...*/     new webpack.optimize.CommonsChunkPlugin({       name: ["vendor", "manifest"], // vendor libs + extracted manifest       minChunks: Infinity,     }),     /*...*/     new ChunkManifestPlugin({ filename: "chunk-manifest.json", manifestVariable: "webpackManifest" })   ]};

因为我们从入口块(entry chunk)中移除了 manifest,所以我们现在有责任为 webpack 提供它。上面示例中的 manifestVariable 选项是全局变量的名称,webpack 将利用它查找 manifest JSON 对象。这个变量应该在我们引入 bundle 到 HTML 之前就定义好。这是通过在 HTML 中内联 JSON 的内容来实现的。我们的 HTML 头部应该像这样:

<!-- 这里我不明白webpackManifest的作用 --><html>   <head>   <script>   //<![CDATA[ window.webpackManifest = {"0":"main.5f020f80c23aa50ebedf.js","1":"vendor.81adc64d405c8b218485.js"} //]]>          </script>   </head>   <body>   </body></html>

在结束时,文件的哈希值应该基于文件的内容。对此,我们可以使用 webpack-chunk-hash 或者 webpack-md5-hash。
所以最终的 webpack.config.js 看起来像这样:

var path = require("path");var webpack = require("webpack");var ChunkManifestPlugin = require("chunk-manifest-webpack-plugin");var WebpackChunkHash = require("webpack-chunk-hash");module.exports = {  entry: {    vendor: "./src/vendor.js", // vendor reference file(s)    main: "./src/index.js" // application code  },  output: {    path: path.join(__dirname, "build"),    filename: "[name].[chunkhash].js",    chunkFilename: "[name].[chunkhash].js"  },  plugins: [    new webpack.optimize.CommonsChunkPlugin({      name: ["vendor", "manifest"], // vendor libs + extracted manifest      minChunks: Infinity,    }),    new webpack.HashedModuleIdsPlugin(),    new WebpackChunkHash(),    new ChunkManifestPlugin({      filename: "chunk-manifest.json",      manifestVariable: "webpackManifest"    })  ]};

使用webpack-dev-server

关于API:https://doc.webpack-china.org/configuration/dev-server/

// package.json// 其中scripts这样设置"scripts": {  "build": "webpack",  "dev": "webpack-dev-server --devtool eval-source-map --progress --colors"},
  • 关于devtool:https://doc.webpack-china.org/configuration/devtool/
  • –progress 打印打包日志
  • –colors带颜色的日志
// webpack.config.jsvar path = require('path');var webpack = require('webpack');var HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = function(env) {  return {    entry: {      main: './index.js',      vendor: ['moment', 'path']    },    output: {      // filename: '[chunkhash].[name].js',      filename: '[name].js',      publicPath: "/assets/",       path: path.resolve(__dirname, 'build')    },    devServer: {      inline: true,      port: 8099,      contentBase: path.join(__dirname, 'build')     },    plugins: [      new webpack.optimize.CommonsChunkPlugin({        names: ['vendor', 'manifest']      }),      new HtmlWebpackPlugin({        template: './index.html'      }),      // etc.    ]  }}

使用npm run dev的时候,可以看到输出有以下:
不会实际生成文件夹,这一部分,推荐看这里:https://github.com/liangklfangl/webpack-dev-server/commit/9b9b86beffedee9c15c7ba3a807b30eb78d477e9

> webpack-dev-server --devtool eval-source-map --progress --colors 10% building modules 2/2 modules 0 activeProject is running at http://localhost:8099/webpack output is served from /assets/Content not from webpack is served from C:\Users\real\...\build 10%Hash: d968bc9b6ab05170f44fVersion: webpack 2.2.1
  • 在 dev-server 的两种不同模式之间切换。默认情况下,应用程序启用内联模式(inline
    mode)。这意味着一段处理实时重载的脚本被插入到你的包(bundle)中,并且构建消息将会出现在浏览器控制台。 也可以使用 iframe模式,它在通知栏下面使用 <iframe> 标签,包含了关于构建的消息。
    切换到 iframe 模式:inline:false
    当使用模块热替换时,建议使用内联模式(inline mode)。

  • output.path:指定编译目录而已(/build/),不能用于html中的js引用。

  • output.publicPath/devServer.publicPath:publicPath:虚拟目录,自动指向path编译目录(/assets/ => /build/)。html中引用js文件时,必须引用此虚拟路径(但实际上引用的是内存中的文件,既不是/build/也不是/assets/)。

  • devServer.contentBase:指明应用根目录,与上面两个配置项毫无关联。

所以在我打开localhost:8099的时候,如果设置了contentBase,那么就会跳到contentBase指明的目录,这里是:C:\Users\real\...\build,这个目录是不会自动生成的,如果手动建立了这个目录,就会去找到这个目录下的index.html文件。否则,不能找到。

实际上可以访问的是:localhost:8099/assets/index.html,访问这个文件,会看到我们写的index.html,其中index.html自动引用了生成的main.js、vendor.js、manifest.js。并且当我们修改js文件的时候,页面会自动刷新

热更新

webpack中文网的一个例子:实测可用。
https://doc.webpack-china.org/guides/hmr-react/

我的在这里:http://blog.csdn.net/real_bird/article/details/62927644

require.ensure

参考自:
http://blog.csdn.net/zhbhun/article/details/46826129
https://doc.webpack-china.org/guides/code-splitting-require/

说明: require.ensure在需要的时候才下载依赖的模块,当参数指定的模块都下载下来了(下载下来的模块还没执行),便执行参数指定的回调函数。require.ensure会创建一个chunk,且可以指定该chunk的名称,如果这个chunk名已经存在了,则将本次依赖的模块合并到已经存在的chunk中,最后这个chunk在webpack构建的时候会单独生成一个文件。

考虑下面的文件结构:

.├── dist├── js│   ├── a.js│   ├── b.js│   ├── c.js│   └── entry.js└── webpack.config.js

entry.js

require('./a');require.ensure(['./b'], function(require){    require('./c');    console.log('done!');});

a.js

console.log('***** I AM a *****');

b.js

console.log('***** I AM b *****');

c.js

console.log('***** I AM c *****');

webpack.config.js

var path = require('path');module.exports = function(env) {    return {        entry: './js/entry.js',        output: {            filename: 'bundle.js',            path: path.resolve(__dirname, 'dist'),            // publicPath: 'https://cdn.example.com/assets/',            // tell webpack where to load the on-demand bundles.            publicPath: __dirname + '/dist/',            pathinfo: true,            // show comments in bundles, just to beautify the output of this example.            // should not be used for production.        }    }}

通过执行这个项目的 webpack 构建,我们发现 webpack 创建了 2 个新的 bundle,bundle.js 和 0.bundle.js。

entry.js 和 a.js 被打包进 bundle.js。b.js和c.js被打包进0.bundle.js。0.bundle.js是按需加载的(通过output.publicPath,这里我修改了,以便能正确加载到)。

index.html

<!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <title>Document</title>  <script src="dist/bundle.js" charset="utf-8"></script></head><body></body></html>

打开这个文件后可以看到,它自动加载了0.bundle.js。
这里写图片描述
而在控制台输出的是:

***** I AM a ********** I AM c *****done!

这就说明了虽然require.ensure中虽然依赖了b.js,但是没有require('./b');,所以就没有打印出来。模块虽然下载了,但必须手动require才会执行。就算没有使用require('./c');,0.bundle.js还是会被加载的。注意到,这里是async

2 0
原创粉丝点击