webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。javascript
当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序须要的每一个模块,而后将全部这些模块打包成一个或多个 bundle。css
mkdir webpack-demo-1 cd webpack-demo-1 npm init -y //生成package.json,而且一路赞成,若是没啥个性化的内容则省了你一路狂按enter npm install --save-dev webpack //安装到开发环境里面(devDependicies)
touch webpack.config.js vi webpack.config.js
配置文件内容以下html
const path = require('path'); module.exports = { entry: './src/index.js', // 这里应用程序开始执行,webpack 开始打包 output: { // webpack 如何输出结果的相关选项 filename: 'bundle.js',//输出资源块的名字(asset chunk) path: path.resolve(__dirname, 'dist') // 全部输出文件的目标路径,个人就是./dist/bundle.js } };
把当前目录的src下的index.js打包到了dist目录下,而且生成了(emmited)一个改头换面的bundle.js
,里面的代码面目全非啊。前端
entry: { scss: './src/css/main.scss', //对象的键名scss 就是输出文件的name bundle: './src/js/app.js' }, output: { filename: "[name].js", path: path.resolve(__dirname, 'dist/js') // publicPath: "/output/" },
多个入口最好写成对象的形式,官网说若是写成了数组,输出的内容会是数组的第一个。java
上述代码会在dist/js
目录下生成scss.js和bundle.js
node
其中,配置文件的第一行代码使用了Node的内置模块path
,而且在它前面加上 __dirname
这个全局变量(也就是第七行代码)。能够防止不一样操做系统之间的文件路径问题,而且可使相对路径按照预期工做。
即便你的index.js内容为空,bundle.js里面也有一些基本的打包代码。webpack
//第一种方法,使用当前目录的node_modules里面的webpack ./node_modules/.bin/webpack //第二种方法使用npm脚本 //首先在你的package.json里面添加下列代码 { ... "scripts": { "build": "webpack" }, ... } //而后,使用下列代码便可 npm run bulid //第三种方法,高版本的npm自带了npx npx webpack //npx会自动查找当前依赖包中的可执行文件,若是找不到,就会去 PATH 里找。若是依然找不到,就会帮你安装!
因此说呢,我选择了第三种使用方法。git
ES6或其余版本js转换成通用js代码,毫无疑问应该使用babel
,不过在webpack
的世界里面统一使用loader
,因此咱们google webpack babel-loader
。
loader 能够将全部类型的文件转换为 webpack 可以处理的有效模块,而后你就能够利用 webpack 的打包能力,对它们进行处理。github
babel-loader
不一样版本的安装脚本、配置文件是不一样的……
(@ο@) 哇~你搜出的最新的文档用这么小的文字告诉你,你用webpack 3.x babel-loader 7.x | babel 6.x
的去这个连接,webpack 3.x | babel-loader 8.x | babel 7.x
的去当前的这连接连接。
好吧,我用上一版本的吧。
因此个人安装脚本是web
npm install --save-dev babel-loader babel-core babel-preset-env webpack
配置文件是
//依然属于webpack.config.js配置的一部分, module: { //这是关于模块的配置 rules: [ //模块规则(配置 loader、解析器等选项) { test: /\.js$/, //使用正则判断后缀是js的文件 exclude: /(node_modules|bower_components)/, //除了这两目录下的node_modules|bower_components use: { loader: 'babel-loader', //用这个loader处理.js的文件 options: { presets: ['env'] //选项,还记得单独使用babel的时候创建的那个.babelrc嘛,就是那个做用。 } } } ] }
借此能够获得loader
的两个做用:
./src/js/
有module-1.js、module-2.js、app.js
三个文件,都是新的语法,用的模块化写法,有的浏览器不支持,因此须要转化。//module-1.js代码 function fn(){ console.log(1) } export default fn //module-2.js function fn(){ console.log(2) } export default fn //app.js import x from './module-1.js' import y from './module-2.js' x() y()
最终效果,打开的个人预览连接,使用ctrl+shift+J
,会看到打印出1和2
若是使用了预编译的scss语言,要把scss文件变成css并加入到html里面,思路同上,google webpack scss
获得以下代码
npm install sass-loader node-sass webpack --save-dev
模块配置文件
// webpack.config.js module.exports = { ... module: { rules: [{ test: /\.scss$/, use: [{ loader: "style-loader" // creates style nodes from JS strings }, { loader: "css-loader" // translates CSS into CommonJS }, { loader: "sass-loader" // compiles Sass to CSS }] }] } };
这个官方的就比较给力了,很清楚地用法
./src/csa/main.scss
编译成main.css不过坑爹依旧☺……用的时候报错喽~
第一次就说缺style-loader,好吧……自觉点把另外一个一块儿安装了把。
npm i --save-dev css-loader style-loader
因此,打开个人预览连接,会看到个人预览的背景是灰色的。
const path = require('path'); module.exports = { entry: './src/js/app.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist/js/') }, module: { rules: [ { test: /\.js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['env'] } } }, { test: /\.scss$/, use: [{ loader: "style-loader" // creates style nodes from JS strings }, { loader: "css-loader" // translates CSS into CommonJS }, { loader: "sass-loader" // compiles Sass to CSS }] } ] } };
因此借助webpack强大的模块化,经过其构建的依赖关系图(dependency graph)把js、scss都搞到了bundle.js里面,真是牛~
原本搞了一个html-loader,优化html,把空格、注释都给压缩掉,提升性能,但是实际使用中也没有报错,也没啥效果,比较尴尬……本身埋个坑后面补一补。
目前呢,前面的loader用的都很爽。在src目录下修改完了代码,一个npx webpack,刷新就能够看到效果了,体验很棒。
可是今天坐在电脑前面,回想代码,之前在前端工程话的道路上,scss、js、html都是被监视着(wacth),开四个命令行窗口,只要src下一有风吹草动,就会把修改后的代码更新过去。
scss、js
了,可我若是修改了src/index.html,dist/也没法获知个人修改啊Copy Webpack Plugin
哎呀,是个plugin
,终于webpack的四大基本概念都到齐了,前面搞了entry output loder
,今天用一下plugin
。
loader 被用于转换某些类型的模块,而插件则能够用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到从新定义环境中的变量。
基本安装
npm i -D copy-webpack-plugin
Copy Webpack Plugin配置文件(plugin的和loader的配置文件可不是一个套路。loader是在module.rules数组的每个对象里面(即rules数组的每个value),而plugin是在module的plugins数组里面)
//依然在webpack.config.js const CopyWebpackPlugin = require('copy-webpack-plugin') const config = { plugins: [ new CopyWebpackPlugin([ ...patterns ], options) ] }
Copy Webpack Plugin的github给的代码,一开始把我搞蒙了,和webpack官网的代码不大同样啊。后来才发现原来用了module.exports = config;
在个人小demo里使用的是
plugins: [ new CopyWebpackPlugin([ { //原来一个plugin就是一个对象啊,使用的时候实例化对象便可 from: 'src/index.html', //从src/index.html目录下复制 to: '../index.html', //到dist/index.html toType: 'file' //复制类型是文件 }], { copyUnmodified: true }) //把未修改的部分也复制过去 ]
这个插件能够实现不少功能,具体的细节看这里
上面代码为何这么写呢 to: '../index.html',
,试了好几遍发现没有报错,就是没有结果,最后搞明白了是路径的问题……
还记得 四大基本概念的output
里面的path吗,回头看一开始的path
output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist/js/') },
项目的path是dist/js
下,因此应该复制到上一级目录下../
也就是dist/
目录下了。
动态效果能够看下图
上述代码有个小问题使用了display: flex
把ul>li
变成了横排,可是这玩意有兼容性。当初个人一篇文章惟一的一个评论就是这么说个人……
检查兼容性(虽然这是严谨要求,我仍是老忘),能够去caniuse 看一下,(@ο@) 哇~IE没有绿的哎,支持太差了。( ⊙ o ⊙ )!万一之后我项目搞大了,IE的用户、老安卓的用户想看我项目咋办呢,只能加一下前缀优化一下啦。
有个挺牛的在线的autoprefixer,也能够去在线转换。
既然使用了webpack就Google webpack autoprefixer
,遗憾的发现autoprefixer
官方推荐使用postcss-loader
先吐槽一下,这货的文档也是稀烂……
npm i -D postcss-loader
module.exports = { parser: 'sugarss', // 铪????解析器是sugarss??? plugins: { 'postcss-import': {}, 'postcss-cssnext': {}, 'cssnano': {} } }
在webpack.config.js的添加时还要注意下面的几点
After setting up your postcss.config.js, add postcss-loader to your webpack.config.js. You can use it standalone or in conjunction with css-loader (recommended). Use it after css-loader and style-loader, but before other preprocessor loaders like e.g sass|less|stylus-loader, if you use any.
这段文档的要点就是让你注意postcss-loader
应该在css-loader style-loader
以后,可是必定要在其余的预处理器preprocessor loaders
以前,例如sass|less|stylus-loader
。
//依然是webpack.config.js module.exports = { module: { rules: [ { test: /\.css$/, use: [ 'style-loader', { loader: 'css-loader', options: { importLoaders: 1 } }, 'postcss-loader' ] } ] } }
本项目用的是.src/css/main.scss
,只能尝试着将上述代码加到相应的位置
rules: [ ... { test: /\.scss$/, use: [{ loader: "style-loader" // creates style nodes from JS strings }, { loader: "css-loader", options: { importLoaders: 1 }// translates CSS into CommonJS }, { loader: "postcss-loader" }, { loader: "sass-loader" // compiles Sass to CSS }] }, ... ]
下面的几点可都是官网文档没写的,只能本身踩一踩的坑……
npx webpack
,连续报错,不过是缺必备的module的错误,也就是缺postcss.config.js里面的postcss-import postcss-cssnext cssnano sugarss
。npm i -D 上面的四个模块名字
,依然报错,此次是语法错误postcss.config.js
里面postcss-loader
哪来的勇气肯定你们都是用的.sss
后缀的sugarss语法呢,还敢直接在文档的醒目位置推荐稀烂的postcss.config.js
,O__O "…注释掉parser: 'sugarss',
这句代码,可使用默认的解析器去解析了,正常运行了。
不过查看代码,发现好像转换后的css有点小丑
仔细观察命令行,发现有线索,一个警告
警告信息提示我说:postcss-cssnext发现有个冗余的autoprefixer
插件在个人postcss插件里面,这个可能有不良影响,我应该移除它,由于它已经包括在了postcss-cssnext里面。
webpack的警告说的很明白,postcss-cssnext是无辜的,并且我肯定按照官网代码走的,没有安装autoprefixer
插件,错误必然在剩下的两个插件里面了。
//修改后的postcss.config.js只剩下这些了 module.exports = { plugins: { 'postcss-import': {}, //1.它错了? 'postcss-cssnext': {}, //webpack告诉我它是清白的 'cssnano': {} //2.它错了? } }
我选择了排除法:
'postcss-import': {},
,发现没法转换后的css代码不对,说明它是无辜的。'cssnano': {}
,终于完美了,并且代码很优美。本着打破砂锅问到底的精神,我搜了一下cssnano
,在其官网看到了真实的错误缘由,webpack很明智啊,诚不欺我,果真冗余插件了。
cssnano里面有autoprefixer
致使了冗余。
webpack 把全部的资源都当成了一个模块, CSS、JS 文件 都是资源, 均可以打包到一个 bundle.js 文件中.
可是有时候须要把样式 单独的打包成一个文件须要抽离出css文件到单独的css/
下。
使用extract-text-webpack-plugin插件能够作到。
npm install extract-text-webpack-plugin --save-dev
const ExtractTextPlugin = require("extract-text-webpack-plugin"); //插件的套路。都要require进来 module.exports = { module: { rules: [ { test: /\.css$/, use: ExtractTextPlugin.extract({ fallback: "style-loader", //失败了就用它解析 use: "css-loader" //是css文件,就用这个处理 }) } ] }, plugins: [ new ExtractTextPlugin("styles.css"), ] }
我若是使用的是scss,就很尴尬了
最开始由一个错误引发
Google一下,解决掉error,fallbak里面使用了style-loader,use里面不该该使用了,那么问题又来了
详见代码注释部分
{ test: /\.scss$/, use: ExtractTextPlugin.extract({ fallback: 'style-loader', //若是在use里面写上style-loader,就报错window未被定义,但是不写的话,个人bundle.js里面就没法把css放到style标签里面,只能手动把分离的css加到index.html,很无语。 use: [{ loader: "css-loader", options: { importLoaders: 1 }// translates CSS into CommonJS }, { loader: "postcss-loader" }, { loader: "sass-loader" // compiles Sass to CSS }] }) }
css/
下,很尴尬,代码未提交,还在摸索中。问题大约知道应该出如今下面这个函数里面
new ExtractTextPlugin({ filename: (getPath) => { return getPath('../main.css').replace('../js', '../css'); // 本意是生成在dist/css/main.css,结果只是在dist/main.css目录下,没有css/ }, allChunks: true })
全部的代码都在个人demo里面。
算……是……搞定了webpack的基本使用了……吧,最简单的符合我目前技术栈的各类loader,plugin都会安装了。
固然,还有无数的webpack的loader、plugin在前方等着我去探索……各类稀奇古怪的配置文件……痛并快乐着☺
五花八门的配置文件挺让我糟心的……幸好有了node爸爸帮我啊,webpack爸爸虽然也是比较严厉的,可是省了你用四个命令行窗口的啊,仍是很感人的啊。
工具这个东西嘛
没有什么bug不是一遍webpack解决不了额,若是有的话,那就来三遍webpaack。总有一天让webpack叫你爸爸!!!
如今的吐槽大概是没有经历过之前更蛋疼的日子吧,幸亏有了新的后起之秀---parcel,它的官网老厉害了,智能提示我用了中文,真是贴心。
回顾一下webpack
的首页
在对比一下parcel
的首页
二者的目的是同样的,不过parcel不须要插件,并且速度快。
没有配置,最好以html或者js为入口,直接npm init -y , parcel index.html
,能够实现index.js。
它会自动帮你打包到dist目录下的一个js文件里面,并复制index.html过去,而这一切只须要上面的一行代码。
parcel index.html
的目录结构而我当时搞webpack的时候的快速开始至少须要安装webpack、webpack.config.js、修改配置内容、安装插件才能实现上述的功能。
当我在parcel-demo
目录下使用parcel index.html
的时候,它自动发现我引入了index.js。
<body> <script src="./index.js"></script> </body>
dist/parcel-demo.js
,我在webpack的时候须要babel-loader还帮我自动下载了node-sass
其余的特色都在官网去发掘吧~但愿往后parcel
快速崛起吧
而如今我仍是要用webpack
的……