webpack:从入门到真实项目配置(二)
2017-09-19 14:08
513 查看
如何在项目中使用 webpack
项目中已经配置了很简单的 babel 和 webpack,直接运行npm run start即可
这时候你会发现这个 bundle.js 居然有这么大,这肯定是不能接受的,所以接下来章节的主要目的就是将单个文件拆分
为多个文件,优化项目。
分离代码
先让我们考虑下缓存机制。对于代码中依赖的库很少会去主动升级版本,但是我们自己的代码却每时每刻都在变更,所以我们可以考虑将依赖的库和自己的代码分割开来,这样用户在下一次使用应用时就可以尽量避免重复下载没有变更的
代码,那么既然要将依赖代码提取出来,我们需要变更下入口和出口的部分代码。
// 这是 packet.json 中 dependencies 下的 const VENOR = ["faker", "lodash", "react", "react-dom", "react-input-range", "react-redux", "redux", "redux-form", "redux-thunk" ] module.exports = { // 之前我们都是使用了单文件入口 // entry 同时也支持多文件入口,现在我们有两个入口 // 一个是我们自己的代码,一个是依赖库的代码 entry: { // bundle 和 vendor 都是自己随便取名的,会映射到 [name] 中 bundle: './src/index.js', vendor: VENOR }, output: { path: path.join(__dirname, 'dist'), filename: '[name].js' }, // ... }
现在我们 build 一下,看看是否有惊喜出现
真的有惊喜。。为什么 bundle 文件大小压根没变。这是因为 bundle 中也引入了依赖库的代码,刚才的步骤并没有抽取
bundle 中引入的代码,接下来让我们学习如何将共同的代码抽取出来。
抽取共同代码
在这小节我们使用 webpack 自带的插件CommonsChunkPlugin。
module.exports = { //... output: { path: path.join(__dirname, 'dist'), // 既然我们希望缓存生效,就应该每次在更改代码以后修改文件名 // [chunkhash]会自动根据文件是否更改而更换哈希 filename: '[name].[chunkhash].js' }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ // vendor 的意义和之前相同 // manifest文件是将每次打包都会更改的东西单独提取出来,保证没有更改的代码无需重新打包,
这样可以加快打包速度
names: ['vendor', 'manifest'], // 配合 manifest 文件使用 minChunks: Infinity }) ] };
当我们重新 build 以后,会发现 bundle 文件很明显的减小了体积
但是我们使用哈希来保证缓存的同时会发现每次 build 都会生成不一样的文件,这时候我们引入另一个插件来帮助我们
删除不需要的文件。
npm install --save-dev clean-webpack-plugin
然后修改配置文件
module.exports = { //... plugins: [ // 只删除 dist 文件夹下的 bundle 和 manifest 文件 new CleanWebpackPlugin(['dist/bundle.*.js','dist/manifest.*.js'], { // 打印 log verbose: true, // 删除文件 dry: false }), ] };
然后 build 的时候会发现以上文件被删除了。
因为我们现在将文件已经打包成三个 JS 了,以后也许会更多,每次新增 JS 文件我们都需要手动在 HTML 中新增标签,
现在我们可以通过一个插件来自动完成这个功能。
npm install html-webpack-plugin --save-dev
然后修改配置文件
module.exports = { //... plugins: [ // 我们这里将之前的 HTML 文件当做模板 // 注意在之前 HTML 文件中请务必删除之前引入的 JS 文件 new HtmlWebpackPlugin({ template: 'index.html' }) ] };
执行 build 操作会发现同时生成了 HTML 文件,并且已经自动引入了 JS 文件
按需加载代码
在这一小节我们将学习如何按需加载代码,在这之前的 vendor 入口我发现忘记加入 router 这个库了,大家可以加入这个库并且重新 build 下,会发现 bundle 只有不到 300KB 了。
现在我们的 bundle 文件包含了我们全部的自己代码。但是当用户访问我们的首页时,其实我们根本无需让用户加载除了
首页以外的代码,这个优化我们可以通过路由的异步加载来完成。
现在修改
src/router.js
// 注意在最新版的 V4路由版本中,更改了按需加载的方式,如果安装了 V4版,可以自行前往官网学习 import React from 'react'; import { Router, Route, IndexRoute, hashHistory } from 'react-router'; import Home from './components/Home'; import ArtistMain from './components/artists/ArtistMain'; const rootRoute = { component: Home, path: '/', indexRoute: { component: ArtistMain }, childRoutes: [ { path: 'artists/new', getComponent(location, cb) { System.import('./components/artists/ArtistCreate') .then(module => cb(null, module.default)) } }, { path: 'artists/:id/edit', getComponent(location, cb) { System.import('./components/artists/ArtistEdit') .then(module => cb(null, module.default)) } }, { path: 'artists/:id', getComponent(location, cb) { System.import('./components/artists/ArtistDetail') .then(module => cb(null, module.default)) } } ] } const Routes = () => { return ( <Router history={hashHistory} routes={rootRoute} /> ); }; export default Routes;
然后执行 build 命令,可以发现我们的 bundle 文件又瘦身了,并且新增了几个文件
将 HTML 文件在浏览器中打开,当点击路由跳转时,可以在开发者工具中的 Network 一栏中看到加载了一个 JS 文件。
首页
点击右上角 Random Artist 以后
自动刷新
每次更新代码都需要执行依次 build,并且还要等上一会很麻烦,这一小节介绍如何使用自动刷新的功能。首先安装插件
npm i --save-dev webpack-dev-server
然后修改 packet.json 文件
"scripts": { "build": "webpack", "dev": "webpack-dev-server --open" },
现在直接执行
npm run dev可以发现浏览器自动打开了一个空的页面,并且在命令行中也多了新的输出
等待编译完成以后,修改 JS 或者 CSS 文件,可以发现 webpack 自动帮我们完成了编译,并且只更新了需要更新的代码
但是每次重新刷新页面对于 debug 来说很不友好,这时候就需要用到模块热替换了。但是因为项目中使用了 React,
并且 Vue 或者其他框架都有自己的一套 hot-loader,所以这里就略过了,有兴趣的可以自己学习下。
生成生产环境代码
现在我们可以将之前所学和一些新加的插件整合在一起,build 生产环境代码。npm i --save-dev url-loader optimize-css-assets-webpack-plugin file-loader
extract-text-webpack-plugin
修改 webpack 配置
var webpack = require('webpack'); var path = require('path'); var HtmlWebpackPlugin = require('html-webpack-plugin') var CleanWebpackPlugin = require('clean-webpack-plugin') var ExtractTextPlugin = require('extract-text-webpack-plugin') var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') const VENOR = ["faker", "lodash", "react", "react-dom", "react-input-range", "react-redux", "redux", "redux-form", "redux-thunk", "react-router" ] module.exports = { entry: { bundle: './src/index.js', vendor: VENOR }, // 如果想修改 webpack-dev-server 配置,在这个对象里面修改 devServer: { port: 8081 }, output: { path: path.join(__dirname, 'dist'), filename: '[name].[chunkhash].js' }, module: { rules: [{ test: /\.js$/, use: 'babel-loader' }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, use: [{ loader: 'url-loader', options: { limit: 10000, name: 'images/[name].[hash:7].[ext]' } }] }, { test: /\.css$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: [{ // 这边其实还可以使用 postcss 先处理下 CSS 代码 loader: 'css-loader' }] }) }, ] }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: ['vendor', 'manifest'], minChunks: Infinity }), new CleanWebpackPlugin(['dist/*.js'], { verbose: true, dry: false }), new HtmlWebpackPlugin({ template: 'index.html' }), // 生成全局变量 new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("process.env.NODE_ENV") }), // 分离 CSS 代码 new ExtractTextPlugin("css/[name].[contenthash].css"), // 压缩提取出的 CSS,并解决ExtractTextPlugin分离出的 JS 重复问题 new OptimizeCSSPlugin({ cssProcessorOptions: { safe: true } }), // 压缩 JS 代码 new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }) ] };
修改 packet.json 文件
"scripts": { "build": "NODE_ENV=production webpack -p", "dev": "webpack-dev-server --open" }
执行
npm run build
可以看到我们在经历了这么多步以后,将 bundle 缩小到了只有 27.1KB,像 vendor 这种常用的库我们一般可以使用
CDN 的方式外链进来。
补充
webpack 配置上有些实用的小点在上文没有提到,统一在这里提一下。module.exports = { resolve: { // 文件扩展名,写明以后就不需要每个文件写后缀 extensions: ['.js', '.css', '.json'], // 路径别名,比如这里可以使用 css 指向 static/css 路径 alias: { '@': resolve('src'), 'css': resolve('static/css') } }, // 生成 source-map,用于打断点,这里有好几个选项 devtool: '#cheap-module-eval-source-map', }
相关文章推荐
- webpack:从入门到真实项目配置
- webpack:从入门到真实项目配置
- webpack实战(二):真实项目中应用系统配置
- Webpack+React项目入门——入门及配置Webpack
- Webpack+React项目入门——入门及配置Webpack
- webpack实战(一):真实项目中一个完整的webpack配置
- vue-cli的webpack模板项目配置文件分析
- vue-cli的webpack模板项目配置文件分析
- vue-cli的webpack模板项目配置文件简析
- webpack从零开始构建项目之启动配置(一)
- webpack入门+react环境配置
- webpack入门+react环境配置
- Vue2+VueRouter2+webpack 构建项目实战(五):配置子路由
- 【vue-cli】vue-cli+webpack配置下局域网,手机无法访问绑定ip的vue项目
- webpack+react项目初体验——记录我的webpack环境配置
- webpack配置项目加载静态资源
- 关于在reactjs项目中如何用webpack配置组件按需加载
- Vue2+VueRouter2+webpack 构建项目实战(三)配置路由,整俩页面先
- webpack入门和实战(一):webpack配置及技巧
- 【22】手动配置webpack项目