webpack
webpack(v3.*)
1、webpack介绍
webpack官网:https://webpack.js.org/
webpack中文官网:https://doc.webpack-china.org...
webpack打包工具源代码:https://github.com/webpack/we...
2、初始化项目
cd yourproject npm init //生成package.json文件 npm install webpack --save-dev
3、webpack.config.js配置文件
(1)、context:上下文,这里省略了,默认为当前文件模块的绝对路径,下面的entry和output中的路径都是相对于context上下文的相对路径.
(2)、output属性:(v3.10.0版本要求path是绝对路径,需要使用node.js的path模块)
注意: path.resolve方法用于将相对路径转为绝对路径。
var path = require("path"); //使用前引入path模块 module.exports = { entry: './src/js/main.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, './dist/js'), publicPath: "https://cdn.example.com/" //用publicPath配置打包后生成线上地址 } }
注意: publicPath,当我们需要上线的时候设置此属性,最后打包的文件路径会被替换为publicPath设置的地址值。
注意: filename: '[name]-[chunkhash].js',filename使用占位符确保每个文件具有唯一的名称。同时使用chunkhash可以达到控制文件版本号的作用,这点与gulp是相通的原理。所以,一旦文件做了修改,再执行webpack,则更改过的文件的chunkhash会发生改变,未做改动的文件的chunkhash不变。
(3)、plugins属性
介绍:plugins 是一个数组,里面是实例化的plugin,即new HtmlWepackPlugin({//code}),这种形式。
① html-webpack-plugin插件:该插件用于生成一个HTML5文件,这个文件用script标签引用所有webpack包。(https://www.npmjs.com,npm官网...
//安装 npm install html-webpack-plugin --save-dev //webpack.config.js配置文件中引入 var HtmlWepackPlugin = require("html-webpack-plugin"); //设置配置项 plugins: [ new HtmlWepackPlugin({ filename:'index-[hash].html', //输出文件名称 template:'index.html', //模板路径 inject:"head", //值:body,head,false;script和link文件注入body或head中,或者false不注入。 chunks:["index","common"], //允许插入到模板中的一些chunk,不配置此项默认会将entry中所有的chunk注入到模板中。多页应用配置多个页面时,每个页面注入的thunk应该是不相同的,需要通过该配置为不同页面注入不同的thunk. excludeChunks: ["constan"], //这个与chunks配置项正好相反,用来配置不允许注入的thunk。 showErrors: true, //值:true/false,默认true;是否将错误信息输出到html页面中。这个很有用,在生成html文件的过程中有错误信息,输出到页面就能看到错误相关信息便于调试。 title:"MyApp", //需要在引用template模板中调用此变量 minify: { //压缩代码 collapseWhitespace: true, //删除空格 html5: true } }) ]
注意: title属性的坑:var HtmlWebpackPlugin = require('html-webpack-plugin'); 这个变量随意。但是在模板中<title><%= htmlWebpackPlugin.options.title %></title>必须使用驼峰式命令。不然会报错一直提示这个插件未定义。
注意: 在页面中引入inline的script方法如下:
在github上,https://github.com/jantimon/h...。共用的main.js以inline的形式引进,a.js,b.js,c.js以外链的形式引进.模板index.html中,
首先在<head>中:
<script type="text/javascript"> <%= compilation.assets[htmlWebpackPlugin.files.chunks.main.entry.substr(htmlWebpackPlugin.files.publicPath.length)].source() %> </script>
重点:!!!compilation.assets是webpack暴露出来可以获取文件数据的方法。通过传文件名路径进这个对象,拿到这个文件的索引,通过调用source拿到文件内容。
compilation.assets需要的是不带publicPath,htmlWebpackPlugin.files.chunks.main.entry带publicPatch,所以用substr()截取。
然后在<body>中:
<%= htmlWebpackPlugin.files.chunks[k].entry %>
最后在webpack.config.js中: inject属性设置为false即可。
(4)、loader属性(以babel-loader为例,用babel-loader将js文件转义为浏览器可识别的js)
module:{ rules:[ //模块规则 { test: /\.js$/, //正则匹配 use: [{ loader:'babel-loader', options:{ presets: ["env"] //采用babel-loader的"env"规则将找的es6,es7,es5语法转码为浏览器可识别的js } }], include: [ path.resolve(__dirname, "/src") //指定babel-loaders寻找的文件路径,注意需是绝对路径 ], exclude: [ path.resolve(__dirname, "/node_modules/") //排除node_modules文件下js,注意需是绝对路径 ] } ] },
注意: webpack官网介绍到:“Rule.loader is a shortcut to Rule.use: [ { loader } ]”. 即下图:
在web开发中浏览器兼容问题,我们不得不使用兼容性前缀,less语言在编译时可以补全css代码的兼容性前缀,但是针对css文件不全前缀需要使用postcss-loader。如下图:
在common.css中引入其他的css文件:
在app.js入口文件中引入common.css,这样打包的时候就能将css文件进行打包:
(6)、wbpack-dev-server
//首先安装插件 npm i webpack-dev-server --save-dev npm i cross-env --save-dev npm i html-webpack-plugin --save-dev
package.json文件:
"scripts":{ //prod环境 "build": "cross-env NODE_ENV=production webpack --config webpack.config.js", //dev环境 "dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js" }
webpack.config.js文件:
const path = require("path") const HTMLWebapckPlugin = require("html-webpack-plugin") const webpack = require('webpack') //引入webpack //在package.json中的“NODE_ENV=development”,可通过下面的process.env读到变量NODE_ENV const isDev = process.env.NODE_ENV === "development" const config = { target:"web",//web平台 entry: path.join(__dirname,'src/index.js'), output:{ filename:'bundle.js', path:path.join(__dirname,"dist") }, module:{ rules:[ { test:/\.vue$/, loader:'vue-loader' }, { test:/\.css$/, use:[ 'style-loader', 'css-loader' ] }, { test:/\.(gif|jpg|jpeg|png|svg)$/, use:[ { loader:'url-loader', options:{ limit:1024, name:'[name]-[hash].[ext]' } } ] } ] }, plugins:[ //使用Vue、react框架时需要DefinePlugin这的插件,因为框架会根据不同环境打包依赖,所以要区分环境从而选择不同的依赖 new webpack.DefinePlugin({ //定义环境变量,对应上面的isDev判断 'process.env':{ NODE_ENV:isDev ? '"development"' : '"production"' //注意此处单引号内还需要双引号 } }), //生成HTML页面 new HTMLWebapckPlugin() ] } //dev环境 if(isDev){ //通过devtool对代码进行映射,可以在浏览器端可以调试 config.devtool = "#cheap-module-eval-sourve-map" //devserver 是在webpack2以后才出现的 config.devServer = { port:'8020', //端口号 host:"0.0.0.0", //设置成这样后,移动端也可以通IP访问页面 //webpack编译时任何错误显示在浏览器中 overlay:{ errors:true, }, open:true,//自动打开浏览器 hot:true //webpack功能:不再重新刷新整个页面,而是局部更新,即热更新 } config.plugins.push( new webpack.HotModuleReplacementPlugin(), //搭配hot:true一起使用 new webpack.NoEmitOnErrorsPlugin() //搭配hot:true一起使用,去除一些不需要展示的信息 ) } module.exports = config
执行npm run dev 就可以通过localhost:8020打开页面
(7)、webpack单独打包css文件
//安装依赖 npm i extract-text-webpack-plugin
在webpack.config.js文件中引用:(结合6中的配置文件)
//dev环境 if(isDev){ config.module.rules.push( { test:/\.scss$/, use:[ 'style-loader', 'css-loader', { loader:'postcss-loader', options:{ sourceMap:true } }, 'sass-loader' ] } ) config.devtool = "#cheap-module-eval-sourve-map" //devserver 是在webpack2以后才出现的 config.devServer = { port:'8020', //端口号 host:"0.0.0.0", //设置成这样后,移动端也可以通IP访问页面 //webpack编译时任何错误显示在浏览器中 overlay:{ errors:true, }, open:true,//自动打开浏览器 hot:true //热更新 } config.plugins.push( new webpack.HotModuleReplacementPlugin(), new webpack.NoEmitOnErrorsPlugin() ) }else{ //正式环境 config.output.filename='[name].[chunkhash:8].js' //正式环境使用chunkhash,dev环境不能使用chunkhash,可使用hash. config.module.rules.push({ test:/\.scss$/, use:ExtractTextWebpack.extract({ fallback:'style-loader', use:[ 'css-loader', { loader:'postcss-loader', options:{ sourceMap:true } }, 'sass-loader' ] }) }) config.plugins.push( new ExtractTextWebpack('style.[contentHash:8].css') ) }
注意:vue组件中的css样式是不会打包到上面的style.[contentHash:8].css文件中的,因为他是异步加载的。
(8)、单独打包类库文件及hash
将类库代码和业务代码分离打包,利用浏览器长期的缓存类库代码。
//正式环境配置 { config.entry = { //业务逻辑代码 app:path.join(__dirname,"src/index.js"), //类库代码在此声明,此处以Vue框架为例 vendor: ['vue'] } config.output.filename='[name].[chunkhash:8].js', config.module.rules.push({ test:/\.scss$/, use:ExtractTextWebpack.extract({ fallback:'style-loader', use:[ 'css-loader', { loader:'postcss-loader', options:{ sourceMap:true } }, 'sass-loader' ] }) }), config.plugins.push( new ExtractTextWebpack('style.[contentHash:8].css'), //单独打包,app中就不会出现类库代码,必须放在runtime之前 new webpack.optimize.CommonsChunkPlugin({ //name属性值要和上面定义的vendor一致 name:'vendor' }), new webpack.optimize.commonsChunkPlugin({ name:'runtime' }) ) }
hash与chunkhash区别:
hash:打包的所有文件共用的一个值 chunkhash:打包的不同的块拥有不同的chunkhash,所以正式环境应使用chunkhash,这样可以保证类库文件不会再每次更改业务重新打包后,又拥有一个新的hash值,而是一直使用之前的chunkhash,这样浏览器就不会在去下载那些依赖,从而实现了缓存。 详细请见:https://www.imooc.com/article/21538