能够经过在执行构建的命令前加一句清除目录的命令
如在package.json里面的build命令修改成javascript
"scripts": { build: rm -rf ./dist && webpack }
比较经常使用的是经过webpack的插件实现css
const { CleanWebpackPlugin } = require('clean-webpack-plugin') modules.export = { plugins: [ new CleanWebpackPlugin() ] }
咱们须要添加css前缀来处理兼容性问题。经过配置postcss-loader来实现。注意是先添加前缀而后再把scss转换成css,因此要写在最下面。html
{ test: /.scss$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader', { loader: 'postcss-loader', options: { plugins: () => [ require('autoprefixer')({ overrideBrowserslist: ['last 2 version', '>1%', 'ios 7'] }) ] } } ] },
modules.export = { plugins: [ new OptimizeCssAssetsWebpackPlugin({ assetNameRegExp: /\.css$/g, cssProcessor: require('cssnano') }) ] }
对于字体大小的兼容,咱们可使用rem做为字体的单位。可是把px转换成rem是一个比较麻烦的计算过程,并且须要对不一样分辨率下的设备,设置不一样的根元素字体大小,从而调整总体的字体大小。一个解决方案就是,在html页面引入flexible.js,再样式文件的loader里面添加px2rem-loader。
引入flexible.js,能够经过直接用script标签引入cdn的连接,也能够经过文件内联的形式,也就是把flexible.js里面的内容,直接嵌入到<script></script>中。这里只介绍内联方式。
因为咱们使用的是html-webpack-plugin把html模板编译到dist下面,因此是支持ejs语法。须要babel-loader把文件的内容转换成兼容性好的代码,而后用raw-loader把文件内容输出成字符串。注意这里的raw-loader安装的是0.5版本。html5
<script> ${require('raw-loader!babel-loader!../../../node_modules/lib-flexible/flexible.js')} </script>
这样咱们打包出来的文件就是java
<script> flexible.js的内容 </script>
添加px2rem-loadernode
{ test: /.scss$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', { loader: 'px2rem-loader', options: { remUnit: 75, // 1px=75rem remPrecision: 8 // 计算rem保留的精度 } }, 'sass-loader', { loader: 'postcss-loader', options: { plugins: () => [ require('autoprefixer')({ overrideBrowserslist: ['last 2 version', '>1%', 'ios 7'] }) ] } } ] }
这里主要是经过动态获取要打包的page路径,生成entry和对应的html-webpack-pluginreact
const setMAP = () => { const entry = {}; const htmlWebpackPlugins = []; const entryFiles = glob.sync(path.join(__dirname, './src/pages/*/index.js')); Object.keys(entryFiles).forEach((index) => { const entryFile = entryFiles[index] const match = entryFile.match(/src\/pages\/(.*)\/index\.js/); const pageName = match && match[1]; entry[pageName] = `./src/pages/${pageName}/index.js` console.log(pageName) htmlWebpackPlugins.push(new HtmlWebpackPlugin({ template: path.join(__dirname, `./src/pages/${pageName}/${pageName}.html`), filename: `${pageName}.html`, chunks: [pageName], inject: true, minify: { html5: true, collapseWhitespace: true, preserveLineBreaks: false, minifyCSS: true, minifyJS: true, removeComments: false } })) }) return { entry, htmlWebpackPlugins } } const { entry, htmlWebpackPlugins } = setMAP() modules.export = { entry, plugins: [ ].concat(htmlWebpackPlugins) }
一种方案是经过html-webpack-externals-plugin,而后在html里面直接引入组件库的cdn连接webpack
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin') moudles.export = { plugins: [ new HtmlWebpackExternalsPlugin({ externals: [ { module: 'react', entry: '//11.url.cn/now/lib/16.2.0/react.min.js', global: 'React' }, { module: 'react-dom', entry: '//11.url.cn/now/lib/16.2.0/react-dom.min.js', global: 'ReactDom' } ] }) ] }
htmlios
<script type="text/javascript" src="https://11.url.cn/now/lib/16.2.0/react.min.js"></script> <script type="text/javascript" src="https://11.url.cn/now/lib/16.2.0/react-dom.min.js"></script>
另一种方法是经过webpack4的
SplitChunksPlugins实现,顺便提一下,webpack3使用的是commonChunksPluginweb
module.exports = { plugins: [ new HtmlWebpackPlugin({ template: path.join(__dirname, `./src/pages/search/search.html`), filename: `search.html`, chunks: ['vendors', 'common', 'search'], //注意这里要引入vendors跟common inject: true, minify: { html5: true, collapseWhitespace: true, preserveLineBreaks: false, minifyCSS: true, minifyJS: true, removeComments: false } }) ] optimization: { splitChunks: { minSize: 0, cacheGroups: { vendors: { test: /(react|react-dom)/, name: 'vendors', chunks: 'all', priority: -10 // 须要设置权重才能都分离出来 }, common: { name: 'commons', chunks: 'all', minChunks: 2, priority: -20 } } } }, }
ES6还不支持这个功能,须要借助babel插件实现。
npm install @babel/plugin-syntax-dynamic-import --save-dev
在babel的配置文件.babelrc里面添加
{ "plugins": [ "@babel/plugin-syntax-dynamic-import" ] }
使用的时候直接经过import函数引入某个组件
loadComponent () { import("./text.js").then((Text) => { console.log(Text) this.setState({ Text: Text.default // 注意这里设置的是Text.default }) }) }
这样就能够发现,text.js被打包成一个独立的js,当触发loadComponent在浏览器的network里面才看到这个文件。
咱们在build的时候,可能只须要看到报错的日志,能够经过设置stats来控制要显示的日志。同时配合插件friendly-errors-webpack-plugin优化日志的输出。
stats参数:
modules.export { plugins: [ new FriendlyErrorsWebpackPlugin() ], stats: 'errors-only' }
概念:就是在构建的过程当中,删除掉咱们不须要用的代码。<br/>
优化原则:无用代码的判断,是根据DCE原则,某些代码不会被执行,或者是执行后的结果不会被用到,或者是执行的结果被用到的变量并无被使用,这些代码都是无效代码,在tree-shaking中要被优化掉的。<br/>
执行阶段:这里是经过静态分析,在编译阶段实现的<br/>
特色:使用ES6的import方法引入文件是能够进行tree-shaking,require是动态引入的文件,没法进行tree shaking, 由于不会在运行的时候还去分析优化代码。<br/>
如何开启:webpack4的production模式是默认会开启tree-shaking的
webpack在编译的时候,会把import进来的模块用闭包函数包裹,而后经过__webpack_require__的形式使用。这样会致使两个问题。<br/>
一、打包的代码体积比较大。<br/>
二、运行时的内存开销比较大。<br/>
scope hoisting经过把import进来的模块,直接内联到同一个闭包函数中,经过替换变量名的方式,避免代码冲突,来减小代码里面的闭包函数。可是须要注意的是仅仅对只被引入过一次的函数使用这个方案,对屡次被引入的,咱们仍是但愿它是一个独立的闭包模块,便于屡次使用。特色:仅在ES6的import下生效,动态引入的require模式下不起做用。<br/>如何开启:webpack4的production模式是默认会开启tree-shaking的