Web前端面试笔试题目,webpack深入浅出实战系列,从零开始系统化学前端

if (

Object.prototype.hasOwnProperty.call(installedChunks, chunkId) &&

installedChunks[chunkId]

) {

resolves.push(installedChunks[chunkId][0]);

}

// 模块安装完

installedChunks[chunkId] = 0;

}

for (moduleId in moreModules) {

if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {

modules[moduleId] = moreModules[moduleId];

}

}

if (parentJsonpFunction) parentJsonpFunction(data);

while (resolves.length) {

// 执行所有 promise 的 resolve 函数

resolves.shift()();

}

}

function jsonpScriptSrc(chunkId) {

return webpack_require.p + ‘’ + ({}[chunkId] || chunkId) + ‘.bundle.js’;

}

function webpack_require(moduleId) {

// …

}

webpack_require.e = function requireEnsure(chunkId) {

var promises = [];

// …

var script = document.createElement(‘script’);

var onScriptComplete;

script.charset = ‘utf-8’;

script.timeout = 120;

script.src = jsonpScriptSrc(chunkId);

onScriptComplete = function(event) {

// 处理异常,消除副作用

// …

};

var timeout = setTimeout(function() {

onScriptComplete({ type: ‘timeout’, target: script });

}, 120000);

script.onerror = script.onload = onScriptComplete;

document.head.appendChild(script);

// …

// 动态加载模块

return Promise.all(promises);

};

var jsonpArray = (window[‘webpackJsonp’] = window[‘webpackJsonp’] || []);

// 重写数组 push 方法

jsonpArray.push = webpackJsonpCallback;

jsonpArray = jsonpArray.slice();

for (var i = 0; i < jsonpArray.length; i++)

webpackJsonpCallback(jsonpArray[i]);

return webpack_require((webpack_require.s = 0));

})({

‘./src/index.js’: function(module, exports, webpack_require) {

eval(`

const css = webpack_require.e(0).then(webpack_require.t.bind(null, “./src/style/index.css”, 7))

const a = 100;

console.log(a, css)

`);

},

0: function(module, exports, webpack_require) {

eval(module.exports = __webpack_require__("./src/index.js"););

}

});

使用 webpack-chain 重写配置

我们用 webpack-chain 来写 webpack 的配置,原因是 webpack-chain 的方式更加灵活

官方解释

webpack-chain 尝试通过提供可链式或顺流式的 API 创建和修改 webpack 配置。API 的 Key 部分可以由用户指定的名称引用,这有助于跨项目修改配置方式的标准化。

const path = require(‘path’);

const rimraf = require(‘rimraf’);

const Config = require(‘webpack-chain’);

const config = new Config();

const resolve = src => {

return path.join(process.cwd(), src);

};

// 删除 dist 目录

rimraf.sync(‘dist’);

config

// 入口

.entry(‘src/index’)

.add(resolve(‘src/index.js’))

.end()

// 模式

// .mode(process.env.NODE_ENV) 等价下面

.set(‘mode’, process.env.NODE_ENV)

// 出口

.output.path(resolve(‘dist’))

.filename(‘[name].bundle.js’);

config.module

.rule(‘css’)

.test(/.css$/)

.use(‘css’)

.loader(‘css-loader’);

module.exports = config.toConfig();

课时 1 小结

至此课时 1 已经结束了,我们主要做了以下事情

  1. webpack 基础配置

  2. 将 css 通过 css-loader 打包进 js 中

  3. 解析 bundle 如何加载模块的

  4. webpack 如何实现的动态加载模块

学习一个工具我们不仅要看懂它的配置,还要对它的原理一起了解,只有学到框架的精髓,我们才能应对如今大前端如此迅猛的发展。


课题 2:搭建开发环境跟生产环境


本章提要:

  • 目录

  • 实现可插拔配置

  • 构建生产环境

  • 构建开发环境(devServer)

  • 提取 css

  • 自动生成 html

  • 项目测试

目录

│── build

│ │── base.js // 公共部分

│ │── build.js

│ └── dev.js

│── config

│ │── base.js // 基础配置

│ │── css.js // css 配置

│ │── HtmlWebpackPlugin.js // html 配置

│ └── MiniCssExtractPlugin.js // 提取css

│── public // 公共资源

│ └── index.html // html 模版

└── src // 开发目录

│── style

│ └── index.css

└── main.js // 主入口

实现可插拔配置

package.json

{

“scripts”: {

“dev”: “cross-env NODE_ENV=development node build/dev.js”,

“build”: “cross-env NODE_ENV=production node build/build.js”

},

“dependencies”: {

“cross-env”: “^6.0.3”,

“css-loader”: “^3.2.0”,

“cssnano”: “^4.1.10”,

“ora”: “^4.0.3”,

“rimraf”: “^3.0.0”,

“webpack”: “^4.41.2”

},

“devDependencies”: {

“extract-text-webpack-plugin”: “^3.0.2”,

“html-webpack-plugin”: “^3.2.0”,

“mini-css-extract-plugin”: “^0.8.0”,

“vue-cli-plugin-commitlint”: “^1.0.4”,

“webpack-chain”: “^6.0.0”,

“webpack-cli”: “^3.3.10”,

“webpack-dev-server”: “^3.9.0”

}

}

build/base.js

const { findSync } = require(‘…/lib’);

const Config = require(‘webpack-chain’);

const config = new Config();

const files = findSync(‘config’);

const path = require(‘path’);

const resolve = p => {

return path.join(process.cwd(), p);

};

module.exports = () => {

const map = new Map();

files.map(_ => {

const name = _.split(‘/’)

.pop()

.replace(‘.js’, ‘’);

return map.set(name, require(_)(config, resolve));

});

map.forEach(v => v());

return config;

};

构建生产环境

build/build.js

const rimraf = require(‘rimraf’);

const ora = require(‘ora’);

const chalk = require(‘chalk’);

const path = require(‘path’);

// 删除 dist 目录

rimraf.sync(path.join(process.cwd(), ‘dist’));

const config = require(‘./base’)();

const webpack = require(‘webpack’);

const spinner = ora(‘开始构建项目…’);

spinner.start();

webpack(config.toConfig(), function(err, stats) {

spinner.stop();

if (err) throw err;

process.stdout.write(

stats.toString({

colors: true,

modules: false,

children: false,

chunks: false,

chunkModules: false

}) + ‘\n\n’

);

if (stats.hasErrors()) {

console.log(chalk.red(‘构建失败\n’));

process.exit(1);

}

console.log(chalk.cyan(‘build完成\n’));

});

构建开发环境(devServer)

build/dev.js

const config = require(‘./base’)();

const webpack = require(‘webpack’);

const chalk = require(‘chalk’);

const WebpackDevServer = require(‘webpack-dev-server’);

const port = 8080;

const publicPath = ‘/common/’;

config.devServer

.quiet(true)

.hot(true)

.https(false)

.disableHostCheck(true)

.publicPath(publicPath)

.clientLogLevel(‘none’);

const compiler = webpack(config.toConfig());

// 拿到 devServer 参数

const chainDevServer = compiler.options.devServer;

const server = new WebpackDevServer(

compiler,

Object.assign(chainDevServer, {})

);

[‘SIGINT’, ‘SIGTERM’].forEach(signal => {

process.on(signal, () => {

server.close(() => {

process.exit(0);

});

});

});

// 监听端口

server.listen(port);

new Promise(() => {

compiler.hooks.done.tap(‘dev’, stats => {

const empty = ’ ';

const common = `App running at:

  • Local: http://127.0.0.1: p o r t {port} port{publicPath}\n`;

console.log(chalk.cyan(‘\n’ + empty + common));

});

});

提取 css

config/css.js

css 提取 loader 配置

module.exports = (config, resolve) => {

return (lang, test) => {

const baseRule = config.module.rule(lang).test(test);

const normalRule = baseRule.oneOf(‘normal’);

applyLoaders(normalRule);

function applyLoaders(rule) {

rule

.use(‘extract-css-loader’)

.loader(require(‘mini-css-extract-plugin’).loader)

.options({

publicPath: ‘./’

});

rule

.use(‘css-loader’)

.loader(‘css-loader’)

.options({});

}

};

};

css 提取插件 MiniCssExtractPlugin

config/MiniCssExtractPlugin.js

const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’);

module.exports = (config, resolve) => {

return () => {

config

.oneOf(‘normal’)

.plugin(‘mini-css-extract’)

.use(MiniCssExtractPlugin);

};

};

自动生成 html

config/HtmlWebpackPlugin.js

const HtmlWebpackPlugin = require(‘html-webpack-plugin’);

module.exports = (config, resolve) => {

return () => {

config.plugin(‘html’).use(HtmlWebpackPlugin, [

{

template: ‘public/index.html’

}

]);

};

};

项目测试

测试 html 模板

public/index.html

learn_webpack
测试 css 模板

src/style/index.css

.test {

width: 200px;

height: 200px;

color: red;

background-color: orange;

}

程序入口

src/main.js

require(‘./style/index.css’);

const h2 = document.createElement(‘h2’);

h2.className = ‘test’;

h2.innerText = ‘test’;

document.body.append(h2);


课题 3:基础配置之loader


本章提要:

  • 配置 babel

  • 使用 babel 配置 ts

  • ts 静态类型检查

  • 友好错误提示插件

  • 配置样式,style,css、less、sass、postcss 等

  • postcss 配置

  • 编译前后 css 对比

  • 配置 autoprefixer

  • 开启 source map

目录

增加以下文件

│──── config // 配置目录

│ │── babelLoader.js // babel-loader 配置

│ │── ForkTsChecker.js // ts 静态检查

│ │── FriendlyErrorsWebpackPlugin.js // 友好错误提示

│ └── style

│──── src // 开发目录

│ │── style

│ │ │── app.css

│ │ │── index.less // 测试 less

│ │ │── index.scss // 测试 sass

│ │ └── index.postcss // 测试 postcss

│ └── ts

│ └── index.ts // 测试 ts

│── babel.js

│── postcss.config.js // postcss 配置

│── tsconfig.json // ts 配置

└──── dist // 打包后的目录

│── app.bundle.js

│── app.css

└── index.html

配置 babel

config/babelLoader.js

module.exports = (config, resolve) => {

const baseRule = config.module.rule(‘js’).test(/.js│.tsx?$/);

const babelPath = resolve(‘babel.js’);

const babelConf = require(babelPath);

const version = require(resolve(‘node_modules/@babel/core/package.json’))

.version;

return () => {

baseRule

.use(‘babel’)

.loader(require.resolve(‘babel-loader’))

.options(babelConf({ version }));

};

};

使用 babel 配置 ts

这里我们使用 babel 插件 @babel/preset-typescript 将 ts 转成 js,并使用 ForkTsCheckerWebpackPluginForkTsCheckerNotifierWebpackPlugin 插件进行错误提示。

babel.js

module.exports = function(api) {

return {

presets: [

[

‘@babel/preset-env’,

{

targets: {

chrome: 59,

edge: 13,

firefox: 50,

safari: 8

}

}

],

[

‘@babel/preset-typescript’,

{

allExtensions: true

}

]

],

plugins: [

‘@babel/plugin-transform-typescript’,

‘transform-class-properties’,

‘@babel/proposal-object-rest-spread’

]

};

};

ts 静态类型检查

const ForkTsCheckerWebpackPlugin = require(‘fork-ts-checker-webpack-plugin’);

const ForkTsCheckerNotifierWebpackPlugin = require(‘fork-ts-checker-notifier-webpack-plugin’);

module.exports = (config, resolve) => {

return () => {

config.plugin(‘ts-fork’).use(ForkTsCheckerWebpackPlugin, [

{

// 将async设为false,可以阻止Webpack的emit以等待类型检查器/linter,并向Webpack的编译添加错误。

async: false

}

]);

// 将TypeScript类型检查错误以弹框提示

// 如果fork-ts-checker-webpack-plugin的async为false时可以不用

// 否则建议使用,以方便发现错误

config.plugin(‘ts-notifier’).use(ForkTsCheckerNotifierWebpackPlugin, [

{

title: ‘TypeScript’,

excludeWarnings: true,

skipSuccessful: true

}

]);

};

};

友好错误提示插件

config/FriendlyErrorsWebpackPlugin.js

const FriendlyErrorsWebpackPlugin = require(‘friendly-errors-webpack-plugin’);

module.exports = (config, resolve) => {

return () => {

config.plugin(‘error’).use(FriendlyErrorsWebpackPlugin);

};

};

配置样式,style,css、less、sass、postcss 等

module.exports = (config, resolve) => {

const createCSSRule = (lang, test, loader, options = {}) => {

const baseRule = config.module.rule(lang).test(test);

const normalRule = baseRule.oneOf(‘normal’);

normalRule

.use(‘extract-css-loader’)

.loader(require(‘mini-css-extract-plugin’).loader)

.options({

hmr: process.env.NODE_ENV === ‘development’,

publicPath: ‘/’

});

normalRule

.use(‘css-loader’)

.loader(require.resolve(‘css-loader’))

.options({});

normalRule.use(‘postcss-loader’).loader(require.resolve(‘postcss-loader’));

if (loader) {

const rs = require.resolve(loader);

normalRule

.use(loader)

.loader(rs)

.options(options);

}

};

return () => {

createCSSRule(‘css’, /.css$/, ‘css-loader’, {});

createCSSRule(‘less’, /.less$/, ‘less-loader’, {});

createCSSRule(‘scss’, /.scss$/, ‘sass-loader’, {});

createCSSRule(‘postcss’, /.p(ost)?css$/);

};

};

postcss 配置

module.exports = {

plugins: {

‘postcss-px-to-viewport’: {

unitToConvert: ‘px’,

viewportWidth: 750,

unitPrecision: 5,

propList: [‘*’],

viewportUnit: ‘vw’,

fontViewportUnit: ‘vw’,

selectorBlackList: [],

minPixelValue: 1,

mediaQuery: false,

replace: true,

exclude: [],

landscape: false,

landscapeUnit: ‘vw’,

landscapeWidth: 568

}

}

};

编译前后 css 对比

src/style/index.less

/* index.less */

.test {

width: 300px;

}

dist/app.css

/* index.css */

.test {

width: 36.66667vw;

height: 26.66667vw;

color: red;

background-color: orange;

}

/* app.css */

.test {

font-size: 8vw;

}

/* index.less */

.test {

width: 40vw;

}

/* index.scss */

.test {

height: 40vw;

}

/* index.postcss */

.test {

background: green;

height: 26.66667vw;

}

配置 autoprefixer

自动添加 css 前缀

postcss.config.js

module.exports = {

plugins: {

autoprefixer: {

overrideBrowserslist: [

‘> 1%’,

‘last 3 versions’,

‘iOS >= 8’,

‘Android >= 4’,

‘Chrome >= 40’

]

}

}

};

转换前

/* index.css */

.test {

width: 200px;

height: 200px;

color: red;

display: flex;

background-color: orange;

}

转换后

/* index.css */

.test {

width: 26.66667vw;

height: 26.66667vw;

color: red;

display: -webkit-box;

display: -webkit-flex;

display: -ms-flexbox;

display: flex;

background-color: orange;

}

开启 source map

config.devtool(‘cheap-source-map’);

└── dist

│── app.bundle.js

│── app.bundle.js.map

│── app.css

│── app.css.map

└── index.html

在源文件下会有一行注释,证明开启了 sourcemap

/# sourceMappingURL=app.css.map/


课时 4:webpack性能优化


本章讲解

  1. 分离 Manifest

  2. Code Splitting(代码分割)

  3. Bundle Splitting(打包分割)

  4. Tree Shaking(删除死代码)

  5. 开启 gzip

分离 Manifest

module.exports = (config, resolve) => {

return () => {

config

.optimization

.runtimeChunk({

name: “manifest”

})

}

}

Code Splitting

  1. 使用动态 import 或者 require.ensure 语法,在第一节已经讲解

  2. 使用 babel-plugin-import 插件按需引入一些组件库

Bundle Splitting

将公共的包提取到 chunk-vendors 里面,比如你require(‘vue’),webpack 会将 vue 打包进 chunk-vendors.bundle.js

module.exports = (config, resolve) => {

return () => {

config

.optimization.splitChunks({

chunks: ‘async’,

minSize: 30000,

minChunks: 1,

maxAsyncRequests: 3,

maxInitialRequests: 3,

cacheGroups: {

vendors: {

name: chunk-vendors,

test: /[\/]node_modules[\/]/,

priority: -10,

chunks: ‘initial’

},

common: {

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
img

最后

给大家分享一些关于HTML的面试题。


一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

mization

.runtimeChunk({

name: “manifest”

})

}

}

Code Splitting

  1. 使用动态 import 或者 require.ensure 语法,在第一节已经讲解

  2. 使用 babel-plugin-import 插件按需引入一些组件库

Bundle Splitting

将公共的包提取到 chunk-vendors 里面,比如你require(‘vue’),webpack 会将 vue 打包进 chunk-vendors.bundle.js

module.exports = (config, resolve) => {

return () => {

config

.optimization.splitChunks({

chunks: ‘async’,

minSize: 30000,

minChunks: 1,

maxAsyncRequests: 3,

maxInitialRequests: 3,

cacheGroups: {

vendors: {

name: chunk-vendors,

test: /[\/]node_modules[\/]/,

priority: -10,

chunks: ‘initial’

},

common: {

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-ntMvMLKt-1712460318542)]
[外链图片转存中…(img-OTWMJd3P-1712460318544)]
[外链图片转存中…(img-j5U3lRmi-1712460318544)]
[外链图片转存中…(img-6r0yyAEH-1712460318545)]
[外链图片转存中…(img-Gfyizs6k-1712460318545)]
[外链图片转存中…(img-KEBStLJu-1712460318546)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-68zxgaOJ-1712460318546)]

最后

给大家分享一些关于HTML的面试题。

[外链图片转存中…(img-Eg1gcDVk-1712460318546)]
[外链图片转存中…(img-0hb2hNfU-1712460318547)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-7AgPjNOg-1712460318547)]

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值