{"id":21182274,"url":"https://github.com/tangxiangmin/webpack_cdn","last_synced_at":"2025-07-10T00:32:15.073Z","repository":{"id":45213445,"uuid":"106391050","full_name":"tangxiangmin/webpack_cdn","owner":"tangxiangmin","description":"use webpack \u0026 systemJS to manage project js files","archived":false,"fork":false,"pushed_at":"2017-10-16T11:22:45.000Z","size":55,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2023-08-20T04:31:48.739Z","etag":null,"topics":["amd","systemjs","webpack","webpack-cdn"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tangxiangmin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-10-10T08:40:36.000Z","updated_at":"2023-08-20T04:31:48.740Z","dependencies_parsed_at":"2022-09-03T06:11:33.844Z","dependency_job_id":null,"html_url":"https://github.com/tangxiangmin/webpack_cdn","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tangxiangmin%2Fwebpack_cdn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tangxiangmin%2Fwebpack_cdn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tangxiangmin%2Fwebpack_cdn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tangxiangmin%2Fwebpack_cdn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tangxiangmin","download_url":"https://codeload.github.com/tangxiangmin/webpack_cdn/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225606641,"owners_count":17495551,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["amd","systemjs","webpack","webpack-cdn"],"created_at":"2024-11-20T17:56:20.311Z","updated_at":"2024-11-20T17:56:21.000Z","avatar_url":"https://github.com/tangxiangmin.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"webpack第三方模块加载\n===\n\n## 目标\nwebpack在提供便利的同时会带来一些新的问题，将所有的工具代码打包到不同的页面文件中，会导致页面脚本体积太大，且不利于缓存。一种解决思路是将很常用的模块（以及整个项目的依赖库文件）放在CDN，通过导入`externals`来使用外部模块，对于那些只在几个页面内公用的模块，可以将他们进行打包。\n\n然而，webpack只是打包工具，对于`externals`的外部模块，不提供对应的模块加载器功能，而手动在页面上导入大量的外部脚本不是一件很合理的事儿。\n\n这里可以把模块分成三类：\n* CDN模块，通过AMD外部引入模块\n* 纯粹的本地模块，不依赖任何CDN模块，可以使用`ES6`模块或`CommonJS`规范定义\n* 依赖于CDN模块的本地模块，需要遵循`AMD`规范\n\n现在在项目中，采用的是手动将CDN模块以`script`标签引入，然后在`externals`声明外部模块。\n如何科学地管理第三方模块呢？下面是一点思考。\n\n## 参考\n\n* [Require external (unmanaged) file](https://github.com/webpack/webpack/issues/150)\n* [webpack是否支持异步加载CDN的文件？](http://react-china.org/t/webpack-cdn/3706)\n* [Resolving remote or cdn urls](https://github.com/webpack/webpack/issues/240)\n\n## 方案一：requirejs与AMD模块\n* 使用`AMD`加载第三方CDN文件\n* 使用`webpack`打包本地模块\n\n**纯粹的本地模块**\n```js\n// math.js\nvar add = function(a, b){\n    return a + b;\n}\nexport default {\n    add\n}\n```\n\n**依赖于CDN模块的本地模块**\n\n```js\n// red.js\n// 由于jquery文件是AMD形式加入的，而打包的代码是按脚本插入先后顺序执行的，\n// 因此这里会出现 \"$ is not a function\"的错误\n\nimport $ from \"jquery\";\n\nvar redify = function(el){\n    $(el).css(\"color\", \"red\");\n}\n\nexport default {\n    redify\n}\n```\n\n无法通过下面配置解决\n```js\nexternals: {\n    jquery: 'jQuery'\n}\n```\n只能遵循AMD规范\n```js\n// 引入配置文件\nimport \"../require.config\"\n\ndefine(\"blue\", ['jquery', 'layer'], function($){\n    var blueify = function(el){\n        $(el).css(\"color\", \"blue\");\n    }\n\n    var msg = function(el){\n        $(el).on(\"click\", function(){\n            layer.confirm($(this).text());\n        })\n    }\n    \n    return {\n        blueify,\n        msg\n    }    \n})\n```\n\n\n除了CDN模块，后面两种类型的模块都需要进行打包，这可以通过`webpack`简单实现\n\n### 使用方式\n\n建立一个`require.config.js`的配置文件，用于管理所有的外部文件\n```js\nvar require = window.require;\n\n// 外部CDN文件\nrequire.config({\n    baseUrl: '/',\n    paths: {\n        jquery: 'https://cdn.bootcss.com/jquery/3.2.1/jquery',\n        layer: 'https://cdn.bootcss.com/layer/3.0.3/layer',\n        axios: 'http://doufuweb.la/assets/js/lib/axios.min'\n    },\n    shim: {\n        layer: {\n            deps: [\"jquery\"],\n            exports: \"layer\"\n        }\n    }\n})\n\nexport default require;\n```\n\n每个页面都对应一个入口文件，这个入口文件是通过`webpack`输出的\n```html\n\u003cscript src=\"./src/require.js\" data-main='/dist/index'\u003e\u003c/script\u003e\n```\n\n在对应的入口文件源文件中，引入本地模块\n\n```js\nimport require from \"./require.config\"\n\nimport math from \"./src/math.js\"\nimport \"./src/blue\"\n\nrequire([],function(){\n    var sum = math.add(1, 2);\n    console.log(sum);\n})\n\nrequire([\"blue\"], function(blue){\n    blue.blueify(\"#test\");\n    blue.msg(\"#test\");\n})\n```\n在`webpack.config.js`中，为每个页面配置对应的输入和输出\n```js\nvar path = require(\"path\")\n\nmodule.exports = {\n    entry: {\n        // 多个页面导入即可\n        index: path.resolve(__dirname, \"./index.js\")\n    },\n    output: {   \n        filename: \"[name].js\",\n        path: path.resolve(__dirname, './dist/')\n    },\n    externals: {\n        jquery: 'jQuery'\n    }\n}\n```\n\n### 评估\n\n优点：\n\n- 不需要将所有文件都打包，统一管理CDN文件，维护成本更低\n- 通过`AMD`，不需要管理外部文件的相互依赖\n- 通过webpack进行打包本地模块，不需要使用r.js\n\n缺点：\n\n- 依赖于CDN模块的本地模块，只能遵循`AMD`规范定义，即使用`define`，因此需要准确区分模块的id\n- 现有的`Commonjs`迁移到`AMD`模块，工作量比较大，手动迁移容易出问题\n\n### 疑问\n\n为什么webpack没有提供类似的功能，即在加载`externals`的时候，如果没有找到全局变量，则通过AMD加载对应的文件~\n\nwebpack内置了`require`和`define`的方法，但是不能指定url，这样就无法实现上面的功能。正在重新翻文档，希望一切顺利。\n\n突然发现作者**sokra **在这个[issue](https://github.com/webpack/webpack/issues/2592)回复的~\n\n\u003e webpack doesn't take care of the module **loading**. You need to use another library for the loading part\n\n然后找到了方案二。\n\n\n## 方案二：SystemJS脚本加载器\n通过`SystemJS`与`externals`。\n\n### 思路\n回到`webpack`，之所以我们需要在页面中手动引入脚本，是因为`externals`需要获取对应模块的全局变量，然后才能在其他模块中使用。其实现类似于\n```js\nmodule.exports = window.jQuery;\n```\n\n换个思路，只要在执行`webpack`的加载对应，内存中存在对应的全局变量即可，这并不需要我们手动去在页面上添加链接，也就是说，我们只需要一个脚本加载器，可以在对应的依赖脚本加载完毕之后再执行我们的本地模块即可。之前把事情想得太复杂了。\n\n然后发现了[SystemJS](https://www.npmjs.com/package/systemjs)， 这是一款用来加载脚本的插件，对应的浏览器版本提供了与`requirejs`的`load`类似的异步加载功能。\n\n没错，就是你了。有大佬给出了脚本加载器的[简单实现](https://github.com/webpack/webpack/issues/150#issuecomment-275952354)。\n\n### 使用方式\n对着文档，跟`requirejs`的模块加载方式比较类似，\n\n同样先定义一个配置文件，参考[配置参数文档](https://github.com/systemjs/systemjs/blob/aa6d18cfac1c4c1fcd3abe23d3353853edbdadf8/docs/config-api.md)\n```js\nimport SystemJS from \"systemjs\"\n\nSystemJS.config({\n    map: {\n        // jquery: \"//code.jquery.com/jquery.js\",\n        jquery: \"//imgdh.doufu.la/jquery/jquery-3.2.1.min.js\"\n    }\n})\n\nexport default SystemJS\n```\n然后在对应的页面文件上按需引入\n```js\nimport SystemJS from \"./systemjs.config\"\n\n// 测试加载时间\nconsole.time(\"sc\");\nSystemJS.import('jquery').then($=\u003e{\n    console.timeEnd(\"sc\")\n    console.log(\"this is index\");\n\n    // 这里使用对应的逻辑\n    console.log($);\n})\n```\n\nSystemJS再将CDN脚本加载到全局环境之后，会自动移除对应的脚本节点，所以在页面上无法看见对应的`script`标签。\n\n### 评估\n\n优点：\n* 由于只是在执行`externals`之前控制脚本加载，对具体的模块基本没有影响，因此迁移成本低\n* 每个页面文件手动`SystemJS.import`依赖文件，按需加载，方便维护\n\n缺点：\n* ES6的`import`和`export`只能出现在`top level`即最上层，因此本地的模块如果依赖CDN模块，需要使用`CommonJS`的方式定义和使用\n* 需要通过维护`SystemJS.config`和`externals`两个地方的模块声明\n\n总体来说要比方案一的迁移成本低得多。\n\n## 最后\n\n最后决定采用**方案二**，这样，貌似解决了困扰我很久的一个问题。\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftangxiangmin%2Fwebpack_cdn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftangxiangmin%2Fwebpack_cdn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftangxiangmin%2Fwebpack_cdn/lists"}