UNPKG

14.3 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.AureliaPlugin = void 0;
4const webpack_1 = require("webpack");
5const AureliaDependenciesPlugin_1 = require("./AureliaDependenciesPlugin");
6const ConventionDependenciesPlugin_1 = require("./ConventionDependenciesPlugin");
7const DistPlugin_1 = require("./DistPlugin");
8const GlobDependenciesPlugin_1 = require("./GlobDependenciesPlugin");
9const HtmlDependenciesPlugin_1 = require("./HtmlDependenciesPlugin");
10const InlineViewDependenciesPlugin_1 = require("./InlineViewDependenciesPlugin");
11const ModuleDependenciesPlugin_1 = require("./ModuleDependenciesPlugin");
12const PreserveExportsPlugin_1 = require("./PreserveExportsPlugin");
13const PreserveModuleNamePlugin_1 = require("./PreserveModuleNamePlugin");
14const SubFolderPlugin_1 = require("./SubFolderPlugin");
15const Webpack = require("webpack");
16// See comments inside the module to understand why this is used
17const emptyEntryModule = "aurelia-webpack-plugin/runtime/empty-entry";
18class AureliaPlugin {
19 constructor(options = {}) {
20 const opts = this.options = Object.assign({
21 includeAll: false,
22 aureliaConfig: ["standard", "developmentLogging"],
23 dist: "native-modules",
24 features: {},
25 moduleMethods: [],
26 noHtmlLoader: false,
27 // Undocumented safety switch
28 noInlineView: false,
29 noModulePathResolve: false,
30 noWebpackLoader: false,
31 // Ideally we would like _not_ to process conventions in node_modules,
32 // because they should be using @useView and not rely in convention in
33 // the first place. Unfortunately at this point many libs do use conventions
34 // so it's just more helpful for users to process them.
35 // As unlikely as it may seem, a common offender here is tslib, which has
36 // matching (yet unrelated) html files in its distribution. So I am making
37 // a quick exception for that.
38 viewsFor: "**/!(tslib)*.{ts,js}",
39 viewsExtensions: ".html",
40 }, options);
41 if (opts.entry) {
42 opts.entry = Array.isArray(opts.entry) ? opts.entry : [opts.entry];
43 }
44 opts.features = Object.assign({
45 ie: true,
46 svg: true,
47 unparser: true,
48 polyfills: "es2015",
49 }, options.features);
50 }
51 apply(compiler) {
52 const opts = this.options;
53 const features = opts.features;
54 let needsEmptyEntry = false;
55 let dllPlugin = compiler.options.plugins.some(p => p instanceof webpack_1.DllPlugin);
56 let dllRefPlugins = compiler.options.plugins.filter(p => p instanceof webpack_1.DllReferencePlugin);
57 // Make sure the loaders are easy to load at the root like `aurelia-webpack-plugin/html-resource-loader`
58 let resolveLoader = compiler.options.resolveLoader;
59 let alias = resolveLoader.alias || (resolveLoader.alias = {});
60 alias["aurelia-webpack-plugin"] = "aurelia-webpack-plugin/dist";
61 // Our async! loader is in fact just bundle-loader!.
62 alias["async"] = "bundle-loader";
63 // For my own sanity when working on this plugin with `yarn link`,
64 // make sure neither webpack nor Node resolve symlinks.
65 if ("NODE_PRESERVE_SYMLINKS" in process.env) {
66 resolveLoader.symlinks = false;
67 compiler.options.resolve.symlinks = false;
68 }
69 // If we aren't building a DLL, "main" is the default entry point
70 // Note that the 'in' check is because someone may explicitly set aureliaApp to undefined
71 if (!dllPlugin && !("aureliaApp" in opts)) {
72 opts.aureliaApp = "main";
73 }
74 // Uses DefinePlugin to cut out optional features
75 const defines = {
76 AURELIA_WEBPACK_2_0: "true"
77 };
78 if (!features.ie)
79 defines.FEATURE_NO_IE = "true";
80 if (!features.svg)
81 defines.FEATURE_NO_SVG = "true";
82 if (!features.unparser)
83 defines.FEATURE_NO_UNPARSER = "true";
84 definePolyfills(defines, features.polyfills);
85 // Add some dependencies that are not documented with PLATFORM.moduleName
86 // because they are determined at build-time.
87 const dependencies = {
88 // PAL for target
89 "aurelia-bootstrapper": "pal" in opts ? opts.pal : { name: getPAL(compiler.options.target), exports: ['initialize'] },
90 // `aurelia-framework` exposes configuration helpers like `.standardConfiguration()`,
91 // that load plugins, but we can't know if they are actually used or not.
92 // User indicates what he uses at build time in `aureliaConfig` option.
93 // Custom config is performed in use code and can use `.moduleName()` like normal.
94 "aurelia-framework": getConfigModules(opts.aureliaConfig),
95 };
96 let globalDependencies = [];
97 if (opts.dist) {
98 // This plugin enables easy switching to a different module distribution (default for Aurelia is dist/commonjs).
99 let resolve = compiler.options.resolve;
100 let plugins = resolve.plugins || (resolve.plugins = []);
101 plugins.push(new DistPlugin_1.DistPlugin(opts.dist));
102 }
103 if (!opts.noModulePathResolve) {
104 // This plugin enables sub-path in modules that are not at the root (e.g. in a /dist folder),
105 // for example aurelia-chart/pie might resolve to aurelia-chart/dist/commonjs/pie
106 let resolve = compiler.options.resolve;
107 let plugins = resolve.plugins || (resolve.plugins = []);
108 plugins.push(new SubFolderPlugin_1.SubFolderPlugin());
109 }
110 if (opts.includeAll) {
111 // Grab everything approach
112 // This plugin ensures that everything in /src is included in the bundle.
113 // This prevents splitting in several chunks but is super easy to use and setup,
114 // no change in existing code or PLATFORM.nameModule() calls are required.
115 new GlobDependenciesPlugin_1.GlobDependenciesPlugin({ [emptyEntryModule]: opts.includeAll + "/**" }).apply(compiler);
116 needsEmptyEntry = true;
117 }
118 else if (opts.aureliaApp) {
119 // Add aurelia-app entry point.
120 // When using includeAll, we assume it's already included
121 globalDependencies.push({ name: opts.aureliaApp, exports: ["configure"] });
122 }
123 if (!dllPlugin && dllRefPlugins.length > 0) {
124 // Creates delegated entries for all Aurelia modules in DLLs.
125 // This is required for aurelia-loader-webpack to find them.
126 let aureliaModules = dllRefPlugins.map(plugin => {
127 let content = plugin["options"].manifest.content;
128 return Object.keys(content)
129 .map(k => content[k].buildMeta["aurelia-id"])
130 .filter(id => !!id);
131 });
132 globalDependencies = globalDependencies.concat(...aureliaModules);
133 }
134 if (!dllPlugin && !opts.noWebpackLoader) {
135 // Setup aurelia-loader-webpack as the module loader
136 this.addEntry(compiler.options, ["aurelia-webpack-plugin/runtime/pal-loader-entry"]);
137 }
138 if (!opts.noHtmlLoader) {
139 // Ensure that we trace HTML dependencies (always required because of 3rd party libs)
140 // Note that this loader will be in last place, which is important
141 // because it will process the file first, before any other loader.
142 compiler.options.module.rules.push({ test: /\.html?$/i, use: "aurelia-webpack-plugin/html-requires-loader" });
143 }
144 if (!opts.noInlineView) {
145 new InlineViewDependenciesPlugin_1.InlineViewDependenciesPlugin().apply(compiler);
146 }
147 if (globalDependencies.length > 0) {
148 dependencies[emptyEntryModule] = globalDependencies;
149 needsEmptyEntry = true;
150 }
151 if (needsEmptyEntry) {
152 this.addEntry(compiler.options, emptyEntryModule);
153 }
154 compiler.hooks.compilation.tap('AureliaPlugin', (compilation, params) => {
155 compilation.hooks.runtimeRequirementInTree
156 .for(Webpack.RuntimeGlobals.require)
157 .tap('AureliaPlugin', (chunk) => {
158 compilation.addRuntimeModule(chunk, new AureliaExposeWebpackInternal());
159 });
160 });
161 // Aurelia libs contain a few global defines to cut out unused features
162 new webpack_1.DefinePlugin(defines).apply(compiler);
163 // Adds some dependencies that are not documented by `PLATFORM.moduleName`
164 new ModuleDependenciesPlugin_1.ModuleDependenciesPlugin(dependencies).apply(compiler);
165 // This plugin traces dependencies in code that are wrapped in PLATFORM.moduleName() calls
166 new AureliaDependenciesPlugin_1.AureliaDependenciesPlugin(...opts.moduleMethods).apply(compiler);
167 // This plugin adds dependencies traced by html-requires-loader
168 // Note: the config extension point for this one is html-requires-loader.attributes.
169 new HtmlDependenciesPlugin_1.HtmlDependenciesPlugin().apply(compiler);
170 // This plugin looks for companion files by swapping extensions,
171 // e.g. the view of a ViewModel. @useView and co. should use PLATFORM.moduleName().
172 // We use it always even with `includeAll` because libs often don't `@useView` (they should).
173 new ConventionDependenciesPlugin_1.ConventionDependenciesPlugin(opts.viewsFor, opts.viewsExtensions).apply(compiler);
174 // This plugin preserves module names for dynamic loading by aurelia-loader
175 new PreserveModuleNamePlugin_1.PreserveModuleNamePlugin(dllPlugin).apply(compiler);
176 // This plugin supports preserving specific exports names when dynamically loading modules
177 // with aurelia-loader, while still enabling tree shaking all other exports.
178 new PreserveExportsPlugin_1.PreserveExportsPlugin().apply(compiler);
179 }
180 addEntry(options, modules) {
181 var _a, _b;
182 let webpackEntry = options.entry;
183 let entries = Array.isArray(modules) ? modules : [modules];
184 // todo:
185 // probably cant do much here?
186 if (typeof webpackEntry === 'function') {
187 return;
188 }
189 // If entry point unspecified in plugin options; use the first webpack entry point
190 const pluginEntry = (_a = this.options.entry) !== null && _a !== void 0 ? _a : [Object.keys(webpackEntry)[0]];
191 // Ensure array
192 const pluginEntries = Array.isArray(pluginEntry) ? pluginEntry : [pluginEntry];
193 // Add runtime to each entry
194 for (const k of pluginEntries) {
195 // Verify that plugin options entry points are defined in webpack entry points
196 if (!(k in webpackEntry)) {
197 throw new Error('entry key "' + k + '" is not defined in Webpack build, cannot apply runtime.');
198 }
199 let entry = webpackEntry[k];
200 (_b = entry.import) === null || _b === void 0 ? void 0 : _b.unshift(...entries);
201 }
202 }
203}
204exports.AureliaPlugin = AureliaPlugin;
205;
206function getPAL(target) {
207 if (target instanceof Array) {
208 if (target.includes('web') || target.includes('es5')) {
209 return 'aurelia-pal-browser';
210 }
211 // not really sure what to pick from an array
212 target = target[0];
213 }
214 if (target === false) {
215 throw new Error('Invalid target to build for AureliaPlugin.');
216 }
217 switch (target) {
218 case undefined:
219 case "es5":
220 case "web":
221 return "aurelia-pal-browser";
222 case "webworker": return "aurelia-pal-worker";
223 case "electron-renderer": return "aurelia-pal-browser";
224 default: return "aurelia-pal-nodejs";
225 }
226}
227const configModules = {};
228let configModuleNames = {
229 "defaultBindingLanguage": "aurelia-templating-binding",
230 "router": "aurelia-templating-router",
231 "history": "aurelia-history-browser",
232 "defaultResources": "aurelia-templating-resources",
233 "eventAggregator": "aurelia-event-aggregator",
234 "developmentLogging": "aurelia-logging-console",
235};
236// "configure" is the only method used by .plugin()
237for (let c in configModuleNames)
238 configModules[c] = { name: configModuleNames[c], exports: ["configure"] };
239// developmentLogging has a pre-task that uses ConsoleAppender
240configModules["developmentLogging"].exports.push("ConsoleAppender");
241function getConfigModules(config) {
242 if (!config)
243 return undefined;
244 if (!Array.isArray(config))
245 config = [config];
246 // Expand "standard"
247 let i = config.indexOf("standard");
248 if (i >= 0)
249 config.splice(i, 1, "basic", "history", "router");
250 // Expand "basic"
251 i = config.indexOf("basic");
252 if (i >= 0)
253 config.splice(i, 1, "defaultBindingLanguage", "defaultResources", "eventAggregator");
254 return config.map(c => configModules[c]);
255}
256function definePolyfills(defines, polyfills) {
257 if (polyfills === "es2015")
258 return;
259 defines.FEATURE_NO_ES2015 = "true";
260 if (polyfills === "es2016")
261 return;
262 defines.FEATURE_NO_ES2016 = "true";
263 if (polyfills === "esnext")
264 return;
265 defines.FEATURE_NO_ESNEXT = "true";
266 // "none" or invalid option.
267}
268class AureliaExposeWebpackInternal extends Webpack.RuntimeModule {
269 constructor() {
270 super("Aurelia expose webpack internal");
271 }
272 /**
273 * @returns {string} runtime code
274 */
275 generate() {
276 return Webpack.Template.asString([
277 "if (typeof __webpack_modules__ !== 'undefined') {",
278 "__webpack_require__.m = __webpack_require__.m || __webpack_modules__;",
279 "__webpack_require__.c = __webpack_require__.c || __webpack_module_cache__;",
280 "}",
281 ]);
282 }
283}